diff --git a/README.md b/README.md index 9daeafb..c57fdec 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -test +idrocap_wa -> Web Application + diff --git a/idrocap_wa/.htaccess b/idrocap_wa/.htaccess new file mode 100644 index 0000000..e029162 --- /dev/null +++ b/idrocap_wa/.htaccess @@ -0,0 +1,12 @@ +# Uncomment the following to prevent the httpoxy vulnerability +# See: https://httpoxy.org/ +# +# RequestHeader unset Proxy +# + + + RewriteEngine on + RewriteRule ^(\.well-known/.*)$ $1 [L] + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + \ No newline at end of file diff --git a/idrocap_wa/Dockerfile b/idrocap_wa/Dockerfile new file mode 100644 index 0000000..4a3d615 --- /dev/null +++ b/idrocap_wa/Dockerfile @@ -0,0 +1,20 @@ +FROM registrywgs.webgenesis.it/webgenesys/jixel/jixel-dockers/almalinux9.5-php8.4.4:latest-master +RUN dnf -y install npm +RUN npm install -g bower +RUN dnf -y install git +RUN mkdir /var/www/jixel +COPY . /var/www/jixel +WORKDIR /var/www/jixel +RUN composer install --no-interaction +WORKDIR /var/www/jixel/webroot +RUN npm install +RUN bower install +EXPOSE 443 +EXPOSE 80 +WORKDIR /var/www/jixel +RUN mkdir /run/php-fpm +COPY ./dockerfiles/run /usr/local/bin/run +RUN chmod 500 /usr/local/bin/run +COPY ./dockerfiles/cake /var/www/jixel/bin/cake +RUN chmod 500 /var/www/jixel/bin/cake +CMD ["run"] diff --git a/idrocap_wa/README.md b/idrocap_wa/README.md new file mode 100644 index 0000000..dae0f2f --- /dev/null +++ b/idrocap_wa/README.md @@ -0,0 +1,61 @@ +# IDROCAP Jixel repository + +Jixel core for IDROCAP developing. Based on [CakePHP](https://cakephp.org) 5.x. + +The framework source code can be found here: [cakephp/cakephp](https://github.com/cakephp/cakephp). + +Before you run the docker stack: +make sure you have a few configs keys under in `config/app_local.php`: + +```php + 'Custom' => [ + 'background_tasks' => [ + 'notifications' => [ + 'channel' => 'newjixel_background_tasks', + ] + ], + ], +``` +and: + +```php + 'Datasources' => [ + 'default' => [ + 'host' => 'mysql8', + 'username' => 'jixel', + 'password' => 'jixel2023', + 'database' => 'jixel', + 'url' => env('DATABASE_URL', null), + ], + 'geo' => [ + 'host' => 'mysql-geo', + 'port' => '3307', + 'username' => 'gecos', + 'password' => 'gecos2015', + 'database' => 'geo', + ], + 'test' => [ + 'host' => 'localhost', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'), + ], + ], +```` + +First bootstrap only (and only if you are mapping in your host machine, idrocapjixel repository): + +enter the container: +`docker exec -it -u jixel` + +install vendor packages: +`composer install -n` + +install vendor front end packages: +`cd webroot` +`npm install -y` +`bower install -y` + + + diff --git a/idrocap_wa/bin/bash_completion.sh b/idrocap_wa/bin/bash_completion.sh new file mode 100644 index 0000000..a3d3feb --- /dev/null +++ b/idrocap_wa/bin/bash_completion.sh @@ -0,0 +1,47 @@ +# +# Bash completion file for CakePHP console. +# Copy this file to a file named `cake` under `/etc/bash_completion.d/`. +# For more info check https://book.cakephp.org/4/en/console-commands/completion.html#how-to-enable-bash-autocompletion-for-the-cakephp-console +# + +_cake() +{ + local cur prev opts cake + COMPREPLY=() + cake="${COMP_WORDS[0]}" + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + if [[ "$cur" == -* ]] ; then + if [[ ${COMP_CWORD} = 1 ]] ; then + opts=$(${cake} completion options) + elif [[ ${COMP_CWORD} = 2 ]] ; then + opts=$(${cake} completion options "${COMP_WORDS[1]}") + else + opts=$(${cake} completion options "${COMP_WORDS[1]}" "${COMP_WORDS[2]}") + fi + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + if [[ ${COMP_CWORD} = 1 ]] ; then + opts=$(${cake} completion commands) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + if [[ ${COMP_CWORD} = 2 ]] ; then + opts=$(${cake} completion subcommands $prev) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + if [[ $COMPREPLY = "" ]] ; then + _filedir + return 0 + fi + return 0 + fi + + return 0 +} + +complete -F _cake cake bin/cake diff --git a/idrocap_wa/bin/cake b/idrocap_wa/bin/cake new file mode 100755 index 0000000..4b696c8 --- /dev/null +++ b/idrocap_wa/bin/cake @@ -0,0 +1,75 @@ +#!/usr/bin/env sh +################################################################################ +# +# Cake is a shell script for invoking CakePHP shell commands +# +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project +# @since 1.2.0 +# @license https://opensource.org/licenses/mit-license.php MIT License +# +################################################################################ + +# Canonicalize by following every symlink of the given name recursively +canonicalize() { + NAME="$1" + if [ -f "$NAME" ] + then + DIR=$(dirname -- "$NAME") + NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") + fi + while [ -h "$NAME" ]; do + DIR=$(dirname -- "$NAME") + SYM=$(readlink "$NAME") + NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") + done + echo "$NAME" +} + +# Find a CLI version of PHP +findCliPhp() { + for TESTEXEC in php php-cli /usr/local/bin/php + do + SAPI=$(echo "" | $TESTEXEC 2>/dev/null) + if [ "$SAPI" = "cli" ] + then + echo $TESTEXEC + return + fi + done + echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 + echo "php"; +} + +# If current path is a symlink, resolve to real path +realname="$0" +if [ -L "$realname" ] +then + realname=$(readlink -f "$0") +fi + +CONSOLE=$(dirname -- "$(canonicalize "$realname")") +APP=$(dirname "$CONSOLE") + +# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment +# variable with the correct path in it. +if [ -z "$PHP" ] +then + PHP=$(findCliPhp) +fi + +if [ "$(basename "$realname")" != 'cake' ] +then + exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" +else + exec "$PHP" "$CONSOLE"/cake.php "$@" +fi + +exit diff --git a/idrocap_wa/bin/cake.bat b/idrocap_wa/bin/cake.bat new file mode 100644 index 0000000..a8a9af2 --- /dev/null +++ b/idrocap_wa/bin/cake.bat @@ -0,0 +1,27 @@ +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Cake is a Windows batch script for invoking CakePHP shell commands +:: +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: +:: Licensed under The MIT License +:: Redistributions of files must retain the above copyright notice. +:: +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project +:: @since 2.0.0 +:: @license https://opensource.org/licenses/mit-license.php MIT License +:: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +@echo off + +SET app=%0 +SET lib=%~dp0 + +php "%lib%cake.php" %* + +echo. + +exit /B %ERRORLEVEL% diff --git a/idrocap_wa/bin/cake.php b/idrocap_wa/bin/cake.php new file mode 100644 index 0000000..aab8d9f --- /dev/null +++ b/idrocap_wa/bin/cake.php @@ -0,0 +1,10 @@ +#!/usr/bin/php -q +run($argv)); diff --git a/idrocap_wa/composer.json b/idrocap_wa/composer.json new file mode 100644 index 0000000..086c0c3 --- /dev/null +++ b/idrocap_wa/composer.json @@ -0,0 +1,67 @@ +{ + "name": "cakephp/app", + "description": "CakePHP skeleton app", + "homepage": "https://cakephp.org", + "type": "project", + "license": "MIT", + "require": { + "php": ">=8.1", + "arodu/cakelte": "^2.0", + "aws/aws-sdk-php": "^3.301", + "cakephp/authentication": "^3.0", + "cakephp/cakephp": "^5.0.1", + "cakephp/migrations": "^4.0.0", + "cakephp/plugin-installer": "^2.0", + "firebase/php-jwt": "^6.10", + "friendsofcake/cakephp-csvview": "^5.0", + "lordsimal/cakephp-sentry": "^3.0", + "mobiledetect/mobiledetectlib": "^3.74", + "muffin/trash": "^4.0", + "php-amqplib/php-amqplib": "^3.6", + "simpleenergy/php-webhdfs": "^1.0" + }, + "require-dev": { + "cakephp/bake": "^3.0.0", + "cakephp/cakephp-codesniffer": "^5.0", + "cakephp/debug_kit": "^5.0.0", + "josegonzalez/dotenv": "^4.0", + "phpunit/phpunit": "^10.1.0" + }, + "suggest": { + "markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.", + "dereuromark/cakephp-ide-helper": "After baking your code, this keeps your annotations in sync with the code evolving from there on for maximum IDE and PHPStan/Psalm compatibility.", + "phpstan/phpstan": "PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code.", + "cakephp/repl": "Console tools for a REPL interface for CakePHP applications." + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Test\\": "tests/", + "Cake\\Test\\": "vendor/cakephp/cakephp/tests/" + } + }, + "scripts": { + "post-install-cmd": "App\\Console\\Installer::postInstall", + "post-create-project-cmd": "App\\Console\\Installer::postInstall", + "check": [ + "@test", + "@cs-check" + ], + "cs-check": "phpcs --colors -p", + "cs-fix": "phpcbf --colors -p", + "stan": "phpstan analyse", + "test": "phpunit --colors=always" + }, + "config": { + "platform-check": true, + "sort-packages": true, + "allow-plugins": { + "cakephp/plugin-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/idrocap_wa/composer.lock b/idrocap_wa/composer.lock new file mode 100644 index 0000000..3da6955 --- /dev/null +++ b/idrocap_wa/composer.lock @@ -0,0 +1,7466 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "e213713928c919df6ae66477bb3a0300", + "packages": [ + { + "name": "almasaeed2010/adminlte", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/ColorlibHQ/AdminLTE.git", + "reference": "bd4d9c72931f1dd28601b6bfb387554a381ad540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ColorlibHQ/AdminLTE/zipball/bd4d9c72931f1dd28601b6bfb387554a381ad540", + "reference": "bd4d9c72931f1dd28601b6bfb387554a381ad540", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Colorlib" + } + ], + "description": "AdminLTE - admin control panel and dashboard that's based on Bootstrap 4", + "homepage": "https://adminlte.io/", + "keywords": [ + "JS", + "admin", + "back-end", + "css", + "less", + "responsive", + "template", + "theme", + "web" + ], + "support": { + "issues": "https://github.com/ColorlibHQ/AdminLTE/issues", + "source": "https://github.com/ColorlibHQ/AdminLTE/tree/v3.2.0" + }, + "time": "2022-02-07T20:33:09+00:00" + }, + { + "name": "arodu/cakelte", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/arodu/cakelte.git", + "reference": "0077bdd47e848122d665f55fa391cad067e8b454" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/arodu/cakelte/zipball/0077bdd47e848122d665f55fa391cad067e8b454", + "reference": "0077bdd47e848122d665f55fa391cad067e8b454", + "shasum": "" + }, + "require": { + "almasaeed2010/adminlte": "^3.2", + "cakephp/cakephp": "^5.0", + "friendsofcake/bootstrap-ui": "^5.0" + }, + "require-dev": { + "cakedc/cakephp-phpstan": "^3.1", + "cakephp/cakephp-codesniffer": "^5.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.1.0" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "CakeLte\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "CakeLTE: AdminLTE plugin for CakePHP", + "support": { + "issues": "https://github.com/arodu/cakelte/issues", + "source": "https://github.com/arodu/cakelte/tree/v2.0.1" + }, + "time": "2024-03-05T11:41:23+00:00" + }, + { + "name": "aws/aws-crt-php", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" + }, + "time": "2024-10-18T22:15:13+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.340.2", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "22cee29c0ca8d93a7a9c03d13739217373a21fcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/22cee29c0ca8d93a7a9c03d13739217373a21fcc", + "reference": "22cee29c0ca8d93a7a9c03d13739217373a21fcc", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.2.3", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^2.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "symfony/filesystem": "^v6.4.0 || ^v7.1.0", + "yoast/phpunit-polyfills": "^2.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + }, + "exclude-from-classmap": [ + "src/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.340.2" + }, + "time": "2025-02-26T19:28:12+00:00" + }, + { + "name": "cakephp/authentication", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/authentication.git", + "reference": "3583745feb37c5069930cd1661bb0723a8f64f99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/authentication/zipball/3583745feb37c5069930cd1661bb0723a8f64f99", + "reference": "3583745feb37c5069930cd1661bb0723a8f64f99", + "shasum": "" + }, + "require": { + "cakephp/http": "^5.0", + "laminas/laminas-diactoros": "^3.0", + "psr/http-client": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0" + }, + "require-dev": { + "cakephp/cakephp": "^5.1.0", + "cakephp/cakephp-codesniffer": "^5.0", + "firebase/php-jwt": "^6.2", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "suggest": { + "cakephp/cakephp": "Install full core to use \"CookieAuthenticator\".", + "cakephp/orm": "To use \"OrmResolver\" (Not needed separately if using full CakePHP framework).", + "cakephp/utility": "Provides CakePHP security methods. Required for the JWT adapter and Legacy password hasher.", + "ext-ldap": "Make sure this php extension is installed and enabled on your system if you want to use the built-in LDAP adapter for \"LdapIdentifier\".", + "firebase/php-jwt": "If you want to use the JWT adapter add this dependency" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Authentication\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/authentication/graphs/contributors" + } + ], + "description": "Authentication plugin for CakePHP", + "homepage": "https://cakephp.org", + "keywords": [ + "Authentication", + "auth", + "cakephp", + "middleware" + ], + "support": { + "docs": "https://book.cakephp.org/authentication/3/en/", + "forum": "https://discourse.cakephp.org/", + "issues": "https://github.com/cakephp/authentication/issues", + "source": "https://github.com/cakephp/authentication" + }, + "time": "2024-10-18T15:48:32+00:00" + }, + { + "name": "cakephp/cakephp", + "version": "5.1.6", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp.git", + "reference": "4b8915cf32949cac5c798af2ff65f688c4d76d21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/4b8915cf32949cac5c798af2ff65f688c4d76d21", + "reference": "4b8915cf32949cac5c798af2ff65f688c4d76d21", + "shasum": "" + }, + "require": { + "cakephp/chronos": "^3.1", + "composer/ca-bundle": "^1.5", + "ext-intl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "laminas/laminas-diactoros": "^3.3", + "laminas/laminas-httphandlerrunner": "^2.6", + "league/container": "^4.2", + "php": ">=8.1", + "psr/container": "^1.1 || ^2.0", + "psr/http-client": "^1.0.2", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0.2", + "psr/http-server-middleware": "^1.0.2", + "psr/log": "^3.0", + "psr/simple-cache": "^2.0 || ^3.0" + }, + "provide": { + "psr/container-implementation": "^2.0", + "psr/http-client-implementation": "^1.0", + "psr/http-factory-implementation": "^1.0", + "psr/http-server-handler-implementation": "^1.0", + "psr/http-server-middleware-implementation": "^1.0", + "psr/log-implementation": "^3.0", + "psr/simple-cache-implementation": "^3.0" + }, + "replace": { + "cakephp/cache": "self.version", + "cakephp/collection": "self.version", + "cakephp/console": "self.version", + "cakephp/core": "self.version", + "cakephp/database": "self.version", + "cakephp/datasource": "self.version", + "cakephp/event": "self.version", + "cakephp/form": "self.version", + "cakephp/http": "self.version", + "cakephp/i18n": "self.version", + "cakephp/log": "self.version", + "cakephp/orm": "self.version", + "cakephp/utility": "self.version", + "cakephp/validation": "self.version" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "http-interop/http-factory-tests": "^2.0", + "mikey179/vfsstream": "^1.6.10", + "mockery/mockery": "^1.6", + "paragonie/csp-builder": "^2.3 || ^3.0", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "1.12.7", + "phpunit/phpunit": "^10.5.5 || ^11.1.3", + "symplify/phpstan-rules": "^12.4" + }, + "suggest": { + "ext-curl": "To enable more efficient network calls in Http\\Client.", + "ext-openssl": "To use Security::encrypt() or have secure CSRF token generation.", + "paragonie/csp-builder": "CSP builder, to use the CSP Middleware" + }, + "type": "library", + "autoload": { + "files": [ + "src/Core/functions.php", + "src/Error/functions.php", + "src/Collection/functions.php", + "src/I18n/functions.php", + "src/ORM/bootstrap.php", + "src/Routing/functions.php", + "src/Utility/bootstrap.php" + ], + "psr-4": { + "Cake\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp/graphs/contributors" + } + ], + "description": "The CakePHP framework", + "homepage": "https://cakephp.org", + "keywords": [ + "conventions over configuration", + "dry", + "form", + "framework", + "mvc", + "orm", + "psr-7", + "rapid-development", + "validation" + ], + "support": { + "forum": "https://discourse.cakephp.org/", + "issues": "https://github.com/cakephp/cakephp/issues", + "source": "https://github.com/cakephp/cakephp" + }, + "time": "2025-02-23T20:09:05+00:00" + }, + { + "name": "cakephp/chronos", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/cakephp/chronos.git", + "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/786d69e1ee4b735765cbdb5521b9603e9b98d650", + "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1.0 || ^11.1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cake\\Chronos\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + }, + { + "name": "The CakePHP Team", + "homepage": "https://cakephp.org" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "https://cakephp.org", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "issues": "https://github.com/cakephp/chronos/issues", + "source": "https://github.com/cakephp/chronos" + }, + "time": "2024-07-18T03:18:04+00:00" + }, + { + "name": "cakephp/migrations", + "version": "4.5.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/migrations.git", + "reference": "675b494235a3d3d8b76fda6a684f4ab38b5a6f7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/migrations/zipball/675b494235a3d3d8b76fda6a684f4ab38b5a6f7f", + "reference": "675b494235a3d3d8b76fda6a684f4ab38b5a6f7f", + "shasum": "" + }, + "require": { + "cakephp/cache": "^5.0", + "cakephp/orm": "^5.0", + "php": ">=8.1", + "robmorgan/phinx": "^0.16.0" + }, + "require-dev": { + "cakephp/bake": "dev-3.next", + "cakephp/cakephp": "dev-5.next as 5.1.0", + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "suggest": { + "cakephp/bake": "If you want to generate migrations.", + "dereuromark/cakephp-ide-helper": "If you want to have IDE suggest/autocomplete when creating migrations." + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Migrations\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/migrations/graphs/contributors" + } + ], + "description": "Database Migration plugin for CakePHP based on Phinx", + "homepage": "https://github.com/cakephp/migrations", + "keywords": [ + "cakephp", + "migrations" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/migrations/issues", + "source": "https://github.com/cakephp/migrations" + }, + "time": "2025-01-16T15:21:04+00:00" + }, + { + "name": "cakephp/plugin-installer", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/plugin-installer.git", + "reference": "5420701fd47d82fe81805ebee34fbbcef34c52ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/plugin-installer/zipball/5420701fd47d82fe81805ebee34fbbcef34c52ba", + "reference": "5420701fd47d82fe81805ebee34fbbcef34c52ba", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "composer/composer": "^2.0", + "phpunit/phpunit": "^10.1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Cake\\Composer\\Plugin" + }, + "autoload": { + "psr-4": { + "Cake\\Composer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://cakephp.org" + } + ], + "description": "A composer installer for CakePHP 3.0+ plugins.", + "support": { + "issues": "https://github.com/cakephp/plugin-installer/issues", + "source": "https://github.com/cakephp/plugin-installer/tree/2.0.1" + }, + "time": "2023-09-10T10:02:44+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.5.5", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-01-08T16:17:16+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v6.11.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.11.0" + }, + "time": "2025-01-23T05:11:06+00:00" + }, + { + "name": "friendsofcake/bootstrap-ui", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfCake/bootstrap-ui.git", + "reference": "3bd2963c13ff2d829010270669f0a259537acd6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfCake/bootstrap-ui/zipball/3bd2963c13ff2d829010270669f0a259537acd6a", + "reference": "3bd2963c13ff2d829010270669f0a259537acd6a", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.1.4" + }, + "require-dev": { + "cakephp/bake": "^3.0", + "cakephp/cakephp-codesniffer": "^5.1", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "BootstrapUI\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jad Bitar", + "homepage": "http://jadb.io", + "role": "Author" + }, + { + "name": "Others", + "homepage": "https://github.com/friendsofcake/bootstrap-ui/graphs/contributors" + } + ], + "description": "Bootstrap front-end framework support for CakePHP", + "homepage": "http://github.com/friendsofcake/bootstrap-ui", + "keywords": [ + "bootstrap", + "cakephp", + "front-end" + ], + "support": { + "issues": "http://github.com/friendsofcake/bootstrap-ui/issues", + "source": "http://github.com/friendsofcake/bootstrap-ui" + }, + "time": "2024-12-13T06:20:08+00:00" + }, + { + "name": "friendsofcake/cakephp-csvview", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfCake/cakephp-csvview.git", + "reference": "c2e539c6e8a53c4fcbc27bfa3776f535dea96dc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfCake/cakephp-csvview/zipball/c2e539c6e8a53c4fcbc27bfa3776f535dea96dc1", + "reference": "c2e539c6e8a53c4fcbc27bfa3776f535dea96dc1", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "CsvView\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jose Diaz-Gonzalez", + "email": "email@josediazgonzalez.com", + "homepage": "https://josediazgonzalez.com", + "role": "Maintainer" + }, + { + "name": "ADmad", + "homepage": "https://github.com/admad", + "role": "Contributor" + }, + { + "name": "Mark Scherer", + "homepage": "https://github.com/dereuromark", + "role": "Contributor" + }, + { + "name": "Joshua Paling", + "homepage": "https://github.com/joshuapaling", + "role": "Contributor" + }, + { + "name": "Gaurish Sharma", + "homepage": "https://github.com/gaurish", + "role": "Contributor" + }, + { + "name": "Gregory Gaskill", + "homepage": "https://github.com/chronon", + "role": "Contributor" + } + ], + "description": "A CSV View class for CakePHP", + "homepage": "https://github.com/friendsofcake/cakephp-csvview", + "keywords": [ + "cakephp", + "csv", + "export", + "view" + ], + "support": { + "issues": "https://github.com/friendsofcake/cakephp-csvview/issues", + "source": "https://github.com/friendsofcake/cakephp-csvview" + }, + "time": "2023-10-13T18:16:38+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-10-17T10:06:22+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "vimeo/psalm": "^4.3 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" + }, + "time": "2024-11-18T16:19:46+00:00" + }, + { + "name": "laminas/laminas-diactoros", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "143a16306602ce56b8b092a7914fef03c37f9ed2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/143a16306602ce56b8b092a7914fef03c37f9ed2", + "reference": "143a16306602ce56b8b092a7914fef03c37f9ed2", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "conflict": { + "amphp/amp": "<2.6.4" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.1 || ^2.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^2.2.0", + "laminas/laminas-coding-standard": "~2.5.0", + "php-http/psr7-integration-tests": "^1.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\Diactoros", + "config-provider": "Laminas\\Diactoros\\ConfigProvider" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2024-10-14T11:59:49+00:00" + }, + { + "name": "laminas/laminas-httphandlerrunner", + "version": "2.11.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-httphandlerrunner.git", + "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/c428d9f67f280d155637cbe2b7245b5188c8cdae", + "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-message-implementation": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~3.0.0", + "laminas/laminas-diactoros": "^3.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\HttpHandlerRunner\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Laminas\\HttpHandlerRunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Execute PSR-15 RequestHandlerInterface instances and emit responses they generate.", + "homepage": "https://laminas.dev", + "keywords": [ + "components", + "laminas", + "mezzio", + "psr-15", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-httphandlerrunner/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-httphandlerrunner/issues", + "rss": "https://github.com/laminas/laminas-httphandlerrunner/releases.atom", + "source": "https://github.com/laminas/laminas-httphandlerrunner" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2024-10-17T20:37:17+00:00" + }, + { + "name": "league/container", + "version": "4.2.4", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/7ea728b013b9a156c409c6f0fc3624071b742dec", + "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "nette/php-generator": "^3.4", + "nikic/php-parser": "^4.10", + "phpstan/phpstan": "^0.12.47", + "phpunit/phpunit": "^8.5.17", + "roave/security-advisories": "dev-latest", + "scrutinizer/ocular": "^1.8", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev", + "dev-2.x": "2.x-dev", + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "mail@philbennett.co.uk", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], + "support": { + "issues": "https://github.com/thephpleague/container/issues", + "source": "https://github.com/thephpleague/container/tree/4.2.4" + }, + "funding": [ + { + "url": "https://github.com/philipobenito", + "type": "github" + } + ], + "time": "2024-11-10T12:42:13+00:00" + }, + { + "name": "lordsimal/cakephp-sentry", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/LordSimal/cakephp-sentry.git", + "reference": "de9640aeee76c50a7a5e0bc2346e295c7adb292f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/LordSimal/cakephp-sentry/zipball/de9640aeee76c50a7a5e0bc2346e295c7adb292f", + "reference": "de9640aeee76c50a7a5e0bc2346e295c7adb292f", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.1.0", + "php": "^8.1", + "sentry/sentry": "^4.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "mockery/mockery": "^1.6", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "CakeSentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Pfeifer", + "email": "info@pfeiferkevin.at", + "role": "Maintainer" + } + ], + "description": "Sentry plugin for CakePHP", + "support": { + "issues": "https://github.com/LordSimal/cakephp-sentry/issues", + "source": "https://github.com/LordSimal/cakephp-sentry/tree/3.2.0" + }, + "time": "2024-12-31T19:23:16+00:00" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "3.74.3", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "39582ab62f86b40e4edb698159f895929a29c346" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/39582ab62f86b40e4edb698159f895929a29c346", + "reference": "39582ab62f86b40e4edb698159f895929a29c346", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.14", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Detection\\": "src/" + }, + "classmap": [ + "src/MobileDetect.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "https://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "support": { + "issues": "https://github.com/serbanghita/Mobile-Detect/issues", + "source": "https://github.com/serbanghita/Mobile-Detect/tree/3.74.3" + }, + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "time": "2023-10-27T16:28:04+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, + { + "name": "muffin/trash", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/UseMuffin/Trash.git", + "reference": "bbdaab7b2f1848fbce9111daadda1146ef1122a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/UseMuffin/Trash/zipball/bbdaab7b2f1848fbce9111daadda1146ef1122a2", + "reference": "bbdaab7b2f1848fbce9111daadda1146ef1122a2", + "shasum": "" + }, + "require": { + "cakephp/orm": "^5.0.0", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp": "^5.0.0", + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1.0" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Muffin\\Trash\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jad Bitar", + "homepage": "http://jadb.io", + "role": "Author" + }, + { + "name": "ADmad", + "homepage": "https://github.com/ADmad", + "role": "Author" + }, + { + "name": "Others", + "homepage": "https://github.com/usemuffin/trash/graphs/contributors" + } + ], + "description": "Adds soft delete support to CakePHP ORM tables.", + "homepage": "https://github.com/usemuffin/trash", + "keywords": [ + "cakephp", + "muffin", + "orm", + "trash" + ], + "support": { + "issues": "https://github.com/usemuffin/trash/issues", + "source": "https://github.com/usemuffin/trash" + }, + "time": "2025-02-04T07:09:14+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:36:18+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "php-amqplib/php-amqplib", + "version": "v3.7.3", + "source": { + "type": "git", + "url": "https://github.com/php-amqplib/php-amqplib.git", + "reference": "9f50fe69a9f1a19e2cb25596a354d705de36fe59" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/9f50fe69a9f1a19e2cb25596a354d705de36fe59", + "reference": "9f50fe69a9f1a19e2cb25596a354d705de36fe59", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-sockets": "*", + "php": "^7.2||^8.0", + "phpseclib/phpseclib": "^2.0|^3.0" + }, + "conflict": { + "php": "7.4.0 - 7.4.1" + }, + "replace": { + "videlalvaro/php-amqplib": "self.version" + }, + "require-dev": { + "ext-curl": "*", + "nategood/httpful": "^0.2.20", + "phpunit/phpunit": "^7.5|^9.5", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpAmqpLib\\": "PhpAmqpLib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Alvaro Videla", + "role": "Original Maintainer" + }, + { + "name": "Raúl Araya", + "email": "nubeiro@gmail.com", + "role": "Maintainer" + }, + { + "name": "Luke Bakken", + "email": "luke@bakken.io", + "role": "Maintainer" + }, + { + "name": "Ramūnas Dronga", + "email": "github@ramuno.lt", + "role": "Maintainer" + } + ], + "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", + "homepage": "https://github.com/php-amqplib/php-amqplib/", + "keywords": [ + "message", + "queue", + "rabbitmq" + ], + "support": { + "issues": "https://github.com/php-amqplib/php-amqplib/issues", + "source": "https://github.com/php-amqplib/php-amqplib/tree/v3.7.3" + }, + "time": "2025-02-18T20:11:13+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.43", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-12-14T21:12:59+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "robmorgan/phinx", + "version": "0.16.6", + "source": { + "type": "git", + "url": "https://github.com/cakephp/phinx.git", + "reference": "5bad10934336e8cf45d50d529cabfcbe7fe287c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/phinx/zipball/5bad10934336e8cf45d50d529cabfcbe7fe287c5", + "reference": "5bad10934336e8cf45d50d529cabfcbe7fe287c5", + "shasum": "" + }, + "require": { + "cakephp/database": "^5.0.2", + "composer-runtime-api": "^2.0", + "php-64bit": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/config": "^3.4|^4.0|^5.0|^6.0|^7.0", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "cakephp/cakephp": "^5.0.2", + "cakephp/cakephp-codesniffer": "^5.0", + "ext-json": "*", + "ext-pdo": "*", + "phpunit/phpunit": "^9.5.19", + "symfony/yaml": "^3.4|^4.0|^5.0|^6.0|^7.0" + }, + "suggest": { + "ext-json": "Install if using JSON configuration format", + "ext-pdo": "PDO extension is needed", + "symfony/yaml": "Install if using YAML configuration format" + }, + "bin": [ + "bin/phinx" + ], + "type": "library", + "autoload": { + "psr-4": { + "Phinx\\": "src/Phinx/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Morgan", + "email": "robbym@gmail.com", + "homepage": "https://robmorgan.id.au", + "role": "Lead Developer" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com", + "homepage": "https://shadowhand.me", + "role": "Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Developer" + }, + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/phinx/graphs/contributors", + "role": "Developer" + } + ], + "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", + "homepage": "https://phinx.org", + "keywords": [ + "database", + "database migrations", + "db", + "migrations", + "phinx" + ], + "support": { + "issues": "https://github.com/cakephp/phinx/issues", + "source": "https://github.com/cakephp/phinx/tree/0.16.6" + }, + "time": "2024-12-20T23:02:54+00:00" + }, + { + "name": "sentry/sentry", + "version": "4.10.0", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php.git", + "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/2af937d47d8aadb8dab0b1d7b9557e495dd12856", + "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "jean85/pretty-package-versions": "^1.5|^2.0.4", + "php": "^7.2|^8.0", + "psr/log": "^1.0|^2.0|^3.0", + "symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0" + }, + "conflict": { + "raven/raven": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "monolog/monolog": "^1.6|^2.0|^3.0", + "phpbench/phpbench": "^1.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^8.5|^9.6", + "symfony/phpunit-bridge": "^5.2|^6.0|^7.0", + "vimeo/psalm": "^4.17" + }, + "suggest": { + "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Sentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "PHP SDK for Sentry (http://sentry.io)", + "homepage": "http://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "log", + "logging", + "profiling", + "sentry", + "tracing" + ], + "support": { + "issues": "https://github.com/getsentry/sentry-php/issues", + "source": "https://github.com/getsentry/sentry-php/tree/4.10.0" + }, + "funding": [ + { + "url": "https://sentry.io/", + "type": "custom" + }, + { + "url": "https://sentry.io/pricing/", + "type": "custom" + } + ], + "time": "2024-11-06T07:44:19+00:00" + }, + { + "name": "simpleenergy/php-webhdfs", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/michaelbutler/php-WebHDFS.git", + "reference": "3212b98e9444e55aab7d129f002247bdcd0c26c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michaelbutler/php-WebHDFS/zipball/3212b98e9444e55aab7d129f002247bdcd0c26c8", + "reference": "3212b98e9444e55aab7d129f002247bdcd0c26c8", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "org\\apache\\hadoop\\": "src/", + "org\\apache\\hadoop\\tools": "app/models/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "tranch-xiao", + "homepage": "https://github.com/tranch-xiao" + }, + { + "name": "dshap", + "homepage": "https://github.com/dshap" + }, + { + "name": "jacobko", + "homepage": "https://github.com/jacobko" + }, + { + "name": "yosshi", + "homepage": "https://github.com/yosshi" + }, + { + "name": "Sebastian Lagemann", + "email": "sebastian@iqu.com" + } + ], + "description": "PHP WebHDFS, forked from https://github.com/simpleenergy/php-WebHDFS", + "support": { + "issues": "https://github.com/michaelbutler/php-WebHDFS/issues", + "source": "https://github.com/michaelbutler/php-WebHDFS/tree/1.0.8" + }, + "time": "2024-04-22T23:58:10+00:00" + }, + { + "name": "symfony/config", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "7716594aaae91d9141be080240172a92ecca4d44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/7716594aaae91d9141be080240172a92ecca4d44", + "reference": "7716594aaae91d9141be080240172a92ecca4d44", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-22T12:07:01+00:00" + }, + { + "name": "symfony/console", + "version": "v7.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-11T03:49:26+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-25T15:15:23+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-20T11:17:29+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-13T13:31:26+00:00" + } + ], + "packages-dev": [ + { + "name": "brick/varexporter", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/brick/varexporter.git", + "reference": "84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/varexporter/zipball/84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b", + "reference": "84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^9.3", + "psalm/phar": "5.21.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\VarExporter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A powerful alternative to var_export(), which can export closures and objects without __set_state()", + "keywords": [ + "var_export" + ], + "support": { + "issues": "https://github.com/brick/varexporter/issues", + "source": "https://github.com/brick/varexporter/tree/0.5.0" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2024-05-10T17:15:19+00:00" + }, + { + "name": "cakephp/bake", + "version": "3.2.2", + "source": { + "type": "git", + "url": "https://github.com/cakephp/bake.git", + "reference": "165e2bd9cc407b0ea19f8a3b48927c10607f3963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/bake/zipball/165e2bd9cc407b0ea19f8a3b48927c10607f3963", + "reference": "165e2bd9cc407b0ea19f8a3b48927c10607f3963", + "shasum": "" + }, + "require": { + "brick/varexporter": "^0.5.0", + "cakephp/cakephp": "^5.1", + "cakephp/twig-view": "^2.0.0", + "nikic/php-parser": "^5.0.0", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0.0", + "cakephp/debug_kit": "^5.0.0", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Bake\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/bake/graphs/contributors" + } + ], + "description": "Bake plugin for CakePHP", + "homepage": "https://github.com/cakephp/bake", + "keywords": [ + "bake", + "cakephp" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "issues": "https://github.com/cakephp/bake/issues", + "source": "https://github.com/cakephp/bake" + }, + "time": "2025-01-17T14:18:00+00:00" + }, + { + "name": "cakephp/cakephp-codesniffer", + "version": "5.1.4", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp-codesniffer.git", + "reference": "6d0168a18c9fb6802103b41579abdcfba7021790" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/6d0168a18c9fb6802103b41579abdcfba7021790", + "reference": "6d0168a18c9fb6802103b41579abdcfba7021790", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "phpstan/phpdoc-parser": "^1.4.5", + "slevomat/coding-standard": "^8.15", + "squizlabs/php_codesniffer": "^3.9" + }, + "require-dev": { + "phpunit/phpunit": "^9.3.4" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "CakePHP\\": "CakePHP/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp-codesniffer/graphs/contributors" + } + ], + "description": "CakePHP CodeSniffer Standards", + "homepage": "https://cakephp.org", + "keywords": [ + "codesniffer", + "framework" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/cakephp-codesniffer/issues", + "source": "https://github.com/cakephp/cakephp-codesniffer" + }, + "time": "2024-12-18T21:15:44+00:00" + }, + { + "name": "cakephp/debug_kit", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/cakephp/debug_kit.git", + "reference": "b83ec9e0c62480f7cc9639e01cb9310bb7f0816d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/b83ec9e0c62480f7cc9639e01cb9310bb7f0816d", + "reference": "b83ec9e0c62480f7cc9639e01cb9310bb7f0816d", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.1", + "composer/composer": "^2.0", + "doctrine/sql-formatter": "^1.1.3", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/authorization": "^3.0", + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "suggest": { + "ext-pdo_sqlite": "DebugKit needs to store panel data in a database. SQLite is simple and easy to use." + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "DebugKit\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Story", + "homepage": "https://mark-story.com", + "role": "Author" + }, + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/debug_kit/graphs/contributors" + } + ], + "description": "CakePHP Debug Kit", + "homepage": "https://github.com/cakephp/debug_kit", + "keywords": [ + "cakephp", + "debug", + "dev", + "kit" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/debug_kit/issues", + "source": "https://github.com/cakephp/debug_kit" + }, + "time": "2024-12-30T18:48:17+00:00" + }, + { + "name": "cakephp/twig-view", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/cakephp/twig-view.git", + "reference": "b11df8e8734ae556d98b143192377dbc6a6f5360" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/twig-view/zipball/b11df8e8734ae556d98b143192377dbc6a6f5360", + "reference": "b11df8e8734ae556d98b143192377dbc6a6f5360", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.0.0", + "jasny/twig-extensions": "^1.3", + "twig/markdown-extra": "^3.0", + "twig/twig": "^3.11.1" + }, + "conflict": { + "wyrihaximus/twig-view": "*" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "cakephp/debug_kit": "^5.0", + "michelf/php-markdown": "^1.9", + "mikey179/vfsstream": "^1.6.10", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Cake\\TwigView\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp/graphs/contributors" + } + ], + "description": "Twig powered View for CakePHP", + "keywords": [ + "cakephp", + "template", + "twig", + "view" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/twig-view/issues", + "source": "https://github.com/cakephp/twig-view" + }, + "time": "2024-10-11T07:53:08+00:00" + }, + { + "name": "composer/class-map-generator", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/ffe442c5974c44a9343e37a0abcb1cc37319f5b9", + "reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9", + "shasum": "" + }, + "require": { + "composer/pcre": "^2.1 || ^3.1", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.6.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-02-05T10:05:34+00:00" + }, + { + "name": "composer/composer", + "version": "2.8.6", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "937c775a644bd7d2c3dfbb352747488463a6e673" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/937c775a644bd7d2c3dfbb352747488463a6e673", + "reference": "937c775a644bd7d2c3dfbb352747488463a6e673", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.5", + "composer/class-map-generator": "^1.4.0", + "composer/metadata-minifier": "^1.0", + "composer/pcre": "^2.2 || ^3.2", + "composer/semver": "^3.3", + "composer/spdx-licenses": "^1.5.7", + "composer/xdebug-handler": "^2.0.2 || ^3.0.3", + "justinrainbow/json-schema": "^5.3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "react/promise": "^2.11 || ^3.2", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.2", + "seld/signal-handler": "^2.0", + "symfony/console": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/filesystem": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/finder": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/polyfill-php73": "^1.24", + "symfony/polyfill-php80": "^1.24", + "symfony/polyfill-php81": "^1.24", + "symfony/process": "^5.4.35 || ^6.3.12 || ^7.0.3" + }, + "require-dev": { + "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan-deprecation-rules": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-strict-rules": "^1.6.0", + "phpstan/phpstan-symfony": "^1.4.0", + "symfony/phpunit-bridge": "^6.4.3 || ^7.0.1" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "phpstan/rules.neon" + ] + }, + "branch-alias": { + "dev-main": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "https://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/composer/issues", + "security": "https://github.com/composer/composer/security/policy", + "source": "https://github.com/composer/composer/tree/2.8.6" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-02-25T12:03:50+00:00" + }, + { + "name": "composer/metadata-minifier", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/metadata-minifier.git", + "reference": "c549d23829536f0d0e984aaabbf02af91f443207" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/metadata-minifier/zipball/c549d23829536f0d0e984aaabbf02af91f443207", + "reference": "c549d23829536f0d0e984aaabbf02af91f443207", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "composer/composer": "^2", + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\MetadataMinifier\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Small utility library that handles metadata minification and expansion.", + "keywords": [ + "composer", + "compression" + ], + "support": { + "issues": "https://github.com/composer/metadata-minifier/issues", + "source": "https://github.com/composer/metadata-minifier/tree/1.0.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2021-04-07T13:37:33+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, + { + "name": "composer/spdx-licenses", + "version": "1.5.8", + "source": { + "type": "git", + "url": "https://github.com/composer/spdx-licenses.git", + "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Spdx\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "SPDX licenses list and validation library.", + "keywords": [ + "license", + "spdx", + "validator" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/spdx-licenses/issues", + "source": "https://github.com/composer/spdx-licenses/tree/1.5.8" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2023-11-20T07:44:33+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "doctrine/sql-formatter", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/sql-formatter.git", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" + }, + "bin": [ + "bin/sql-formatter" + ], + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\SqlFormatter\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "https://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/doctrine/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "support": { + "issues": "https://github.com/doctrine/sql-formatter/issues", + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.2" + }, + "time": "2025-01-24T11:45:48+00:00" + }, + { + "name": "jasny/twig-extensions", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/jasny/twig-extensions.git", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/8a5ca5f49317bf421a519556ad2e876820d41e01", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01", + "shasum": "" + }, + "require": { + "php": ">=7.4.0", + "twig/twig": "^2.7 | ^3.0" + }, + "require-dev": { + "ext-intl": "*", + "ext-json": "*", + "ext-pcre": "*", + "phpstan/phpstan": "^1.12.0", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.10" + }, + "suggest": { + "ext-intl": "Required for the use of the LocalDate Twig extension", + "ext-pcre": "Required for the use of the PCRE Twig extension" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jasny\\Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Arnold Daniels", + "email": "arnold@jasny.net", + "homepage": "http://www.jasny.net" + } + ], + "description": "A set of useful Twig filters", + "homepage": "http://github.com/jasny/twig-extensions#README", + "keywords": [ + "PCRE", + "array", + "date", + "datetime", + "preg", + "regex", + "templating", + "text", + "time" + ], + "support": { + "issues": "https://github.com/jasny/twig-extensions/issues", + "source": "https://github.com/jasny/twig-extensions" + }, + "time": "2024-09-03T09:04:53+00:00" + }, + { + "name": "josegonzalez/dotenv", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/josegonzalez/php-dotenv.git", + "reference": "e97dbd3db53508dcd536e73ec787a7f11458d41d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/josegonzalez/php-dotenv/zipball/e97dbd3db53508dcd536e73ec787a7f11458d41d", + "reference": "e97dbd3db53508dcd536e73ec787a7f11458d41d", + "shasum": "" + }, + "require": { + "m1/env": "2.*", + "php": ">=5.5.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "~2.0", + "php-mock/php-mock-phpunit": "~1.1||~2.0", + "squizlabs/php_codesniffer": "~2.9||~3.7" + }, + "type": "library", + "autoload": { + "psr-0": { + "josegonzalez\\Dotenv": [ + "src", + "tests" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jose Diaz-Gonzalez", + "email": "dotenv@josegonzalez.com", + "homepage": "http://josediazgonzalez.com", + "role": "Maintainer" + } + ], + "description": "dotenv file parsing for PHP", + "homepage": "https://github.com/josegonzalez/php-dotenv", + "keywords": [ + "configuration", + "dotenv", + "php" + ], + "support": { + "issues": "https://github.com/josegonzalez/php-dotenv/issues", + "source": "https://github.com/josegonzalez/php-dotenv/tree/4.0.0" + }, + "time": "2023-05-29T22:49:26+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" + }, + "time": "2024-07-06T21:00:26+00:00" + }, + { + "name": "m1/env", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/m1/Env.git", + "reference": "5c296e3e13450a207e12b343f3af1d7ab569f6f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/m1/Env/zipball/5c296e3e13450a207e12b343f3af1d7ab569f6f3", + "reference": "5c296e3e13450a207e12b343f3af1d7ab569f6f3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "scrutinizer/ocular": "~1.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "josegonzalez/dotenv": "For loading of .env", + "m1/vars": "For loading of configs" + }, + "type": "library", + "autoload": { + "psr-4": { + "M1\\Env\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Miles Croxford", + "email": "hello@milescroxford.com", + "homepage": "http://milescroxford.com", + "role": "Developer" + } + ], + "description": "Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.", + "homepage": "https://github.com/m1/Env", + "keywords": [ + ".env", + "config", + "dotenv", + "env", + "loader", + "m1", + "parser", + "support" + ], + "support": { + "issues": "https://github.com/m1/Env/issues", + "source": "https://github.com/m1/Env/tree/2.2.0" + }, + "time": "2020-02-19T09:02:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.33.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" + }, + "time": "2024-10-13T11:25:22+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "10.1.16", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^10.1" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-22T04:31:57+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-31T06:24:48+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:56:09+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-31T14:07:24+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:57:52+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "10.5.45", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.12.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.3", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-02-06T16:08:12+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:12:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:58:43+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:59:15+00:00" + }, + { + "name": "sebastian/comparator", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-18T14:56:07+00:00" + }, + { + "name": "sebastian/complexity", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "68ff824baeae169ec9f2137158ee529584553799" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-21T08:37:17+00:00" + }, + { + "name": "sebastian/diff", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:15:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "6.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-23T08:47:14+00:00" + }, + { + "name": "sebastian/exporter", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:17:12+00:00" + }, + { + "name": "sebastian/global-state", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:19:19+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-21T08:38:20+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:08:32+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:06:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:05:40+00:00" + }, + { + "name": "sebastian/type", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:10:45+00:00" + }, + { + "name": "sebastian/version", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-07T11:34:05+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2024-07-11T14:55:45+00:00" + }, + { + "name": "seld/phar-utils", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1" + }, + "time": "2022-08-31T10:31:18+00:00" + }, + { + "name": "seld/signal-handler", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/signal-handler.git", + "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98", + "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^7.5.20 || ^8.5.23", + "psr/log": "^1 || ^2 || ^3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\Signal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development", + "keywords": [ + "posix", + "sigint", + "signal", + "sigterm", + "unix" + ], + "support": { + "issues": "https://github.com/Seldaek/signal-handler/issues", + "source": "https://github.com/Seldaek/signal-handler/tree/2.0.2" + }, + "time": "2023-09-03T09:24:00+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.15.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "7d1d957421618a3803b593ec31ace470177d7817" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2024-03-09T15:20:58+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.11.3", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", + "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-01-23T17:04:15+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-05T08:33:46+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "twig/markdown-extra", + "version": "v3.20.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/markdown-extra.git", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/f4616e1dd375209dacf6026f846e6b537d036ce4", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "erusev/parsedown": "dev-master as 1.x-dev", + "league/commonmark": "^1.0|^2.0", + "league/html-to-markdown": "^4.8|^5.0", + "michelf/php-markdown": "^1.8|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Twig\\Extra\\Markdown\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for Markdown", + "homepage": "https://twig.symfony.com", + "keywords": [ + "html", + "markdown", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/markdown-extra/tree/v3.20.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-01-31T20:45:36+00:00" + }, + { + "name": "twig/twig", + "version": "v3.20.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "3468920399451a384bef53cf7996965f7cd40183" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183", + "reference": "3468920399451a384bef53cf7996965f7cd40183", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.20.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-02-13T08:34:43+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.1" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/idrocap_wa/config/.env.example b/idrocap_wa/config/.env.example new file mode 100644 index 0000000..e90937b --- /dev/null +++ b/idrocap_wa/config/.env.example @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Used as a default to seed config/.env which +# enables you to use environment variables to configure +# the aspects of your application that vary by +# environment. +# +# Having this file in production is considered a **SECURITY RISK** and also decreases +# the bootstrap performance of your application. +# +# To use this file, first copy it into `config/.env`. Also ensure the related +# code block for loading this file is uncommented in `config/bootstrap.php` +# +# In development .env files are parsed by PHP +# and set into the environment. This provides a simpler +# development workflow over standard environment variables. +export APP_NAME="__APP_NAME__" +export DEBUG="true" +export APP_ENCODING="UTF-8" +export APP_DEFAULT_LOCALE="en_US" +export APP_DEFAULT_TIMEZONE="UTC" +export SECURITY_SALT="__SALT__" + +# Uncomment these to define cache configuration via environment variables. +#export CACHE_DURATION="+2 minutes" +#export CACHE_DEFAULT_URL="file:///path/to/tmp/cache/?prefix=${APP_NAME}_default_&duration=${CACHE_DURATION}" +#export CACHE_CAKECORE_URL="file:///path/to/tmp/cache/persistent?prefix=${APP_NAME}_cake_core_&serialize=true&duration=${CACHE_DURATION}" +#export CACHE_CAKEMODEL_URL="file:///path/to/tmp/cache/models?prefix=${APP_NAME}_cake_model_&serialize=true&duration=${CACHE_DURATION}" + +# Uncomment these to define email transport configuration via environment variables. +#export EMAIL_TRANSPORT_DEFAULT_URL="" + +# Uncomment these to define database configuration via environment variables. +#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" +#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" + +# Uncomment these to define logging configuration via environment variables. +#export LOG_DEBUG_URL="file:///path/to/logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug" +#export LOG_ERROR_URL="file:///path/to/logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error" diff --git a/idrocap_wa/config/app.php b/idrocap_wa/config/app.php new file mode 100644 index 0000000..f8f6a0b --- /dev/null +++ b/idrocap_wa/config/app.php @@ -0,0 +1,436 @@ + filter_var(env('DEBUG', false), FILTER_VALIDATE_BOOLEAN), + + /* + * Configure basic information about the application. + * + * - namespace - The namespace to find app classes under. + * - defaultLocale - The default locale for translation, formatting currencies and numbers, date and time. + * - encoding - The encoding used for HTML + database connections. + * - base - The base directory the app resides in. If false this + * will be auto detected. + * - dir - Name of app directory. + * - webroot - The webroot directory. + * - wwwRoot - The file path to webroot. + * - baseUrl - To configure CakePHP to *not* use mod_rewrite and to + * use CakePHP pretty URLs, remove these .htaccess + * files: + * /.htaccess + * /webroot/.htaccess + * And uncomment the baseUrl key below. + * - fullBaseUrl - A base URL to use for absolute links. When set to false (default) + * CakePHP generates required value based on `HTTP_HOST` environment variable. + * However, you can define it manually to optimize performance or if you + * are concerned about people manipulating the `Host` header. + * - imageBaseUrl - Web path to the public images directory under webroot. + * - cssBaseUrl - Web path to the public css directory under webroot. + * - jsBaseUrl - Web path to the public js directory under webroot. + * - paths - Configure paths for non class based resources. Supports the + * `plugins`, `templates`, `locales` subkeys, which allow the definition of + * paths for plugins, view templates and locale files respectively. + */ + 'App' => [ + 'namespace' => 'App', + 'encoding' => env('APP_ENCODING', 'UTF-8'), + 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'it'), + 'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'UTC'), + 'defaultUserTimezone' => 'Europe/Rome', + 'base' => false, + 'dir' => 'src', + 'webroot' => 'webroot', + 'wwwRoot' => WWW_ROOT, + //'baseUrl' => env('SCRIPT_NAME'), + 'fullBaseUrl' => false, + 'imageBaseUrl' => 'img/', + 'cssBaseUrl' => 'css/', + 'jsBaseUrl' => 'js/', + 'paths' => [ + 'plugins' => [ROOT . DS . 'plugins' . DS], + 'templates' => [ROOT . DS . 'templates' . DS], + 'locales' => [RESOURCES . 'locales' . DS], + ], + ], + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT'), + ], + + /* + * Apply timestamps with the last modified time to static assets (js, css, images). + * Will append a querystring parameter containing the time the file was modified. + * This is useful for busting browser caches. + * + * Set to true to apply timestamps when debug is true. Set to 'force' to always + * enable timestamping regardless of debug value. + */ + 'Asset' => [ + //'timestamp' => true, + // 'cacheTime' => '+1 year' + ], + + /* + * Configure the cache adapters. + */ + 'Cache' => [ + 'default' => [ + 'className' => RedisEngine::class, + 'database' => 1, + 'duration' => 3600, + 'groups' => [], + 'password' => false, + 'persistent' => true, + 'port' => 6379, + 'prefix' => '', + 'probability' => 100, + 'host' => null, + 'server' => 'redis', + 'timeout' => 0, + 'unix_socket' => false, + ], + + /* + * Configure the cache used for general framework caching. + * Translation cache files are stored with this configuration. + * Duration will be set to '+2 minutes' in bootstrap.php when debug = true + * If you set 'className' => 'Null' core cache will be disabled. + */ + '_cake_translations_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_core_', + 'path' => CACHE . 'persistent' . DS, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKECORE_URL', null), + ], + + /* + * Configure the cache for model and datasource caches. This cache + * configuration is used to store schema descriptions, and table listings + * in connections. + * Duration will be set to '+2 minutes' in bootstrap.php when debug = true + */ + '_cake_model_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_model_', + 'path' => CACHE . 'models' . DS, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKEMODEL_URL', null), + ], + ], + + /* + * Configure the Error and Exception handlers used by your application. + * + * By default errors are displayed using Debugger, when debug is true and logged + * by Cake\Log\Log when debug is false. + * + * In CLI environments exceptions will be printed to stderr with a backtrace. + * In web environments an HTML page will be displayed for the exception. + * With debug true, framework errors like Missing Controller will be displayed. + * When debug is false, framework errors will be coerced into generic HTTP errors. + * + * Options: + * + * - `errorLevel` - int - The level of errors you are interested in capturing. + * - `trace` - boolean - Whether backtraces should be included in + * logged errors/exceptions. + * - `log` - boolean - Whether you want exceptions logged. + * - `exceptionRenderer` - string - The class responsible for rendering uncaught exceptions. + * The chosen class will be used for both CLI and web environments. If you want different + * classes used in CLI and web environments you'll need to write that conditional logic as well. + * The conventional location for custom renderers is in `src/Error`. Your exception renderer needs to + * implement the `render()` method and return either a string or Http\Response. + * `errorRenderer` - string - The class responsible for rendering PHP errors. The selected + * class will be used for both web and CLI contexts. If you want different classes for each environment + * you'll need to write that conditional logic as well. Error renderers need to + * to implement the `Cake\Error\ErrorRendererInterface`. + * - `skipLog` - array - List of exceptions to skip for logging. Exceptions that + * extend one of the listed exceptions will also be skipped for logging. + * E.g.: + * `'skipLog' => ['Cake\Http\Exception\NotFoundException', 'Cake\Http\Exception\UnauthorizedException']` + * - `extraFatalErrorMemory` - int - The number of megabytes to increase the memory limit by + * when a fatal error is encountered. This allows + * breathing room to complete logging or error handling. + * - `ignoredDeprecationPaths` - array - A list of glob compatible file paths that deprecations + * should be ignored in. Use this to ignore deprecations for plugins or parts of + * your application that still emit deprecations. + */ + 'Error' => [ + 'errorLevel' => E_ALL, + 'skipLog' => [], + 'log' => true, + 'trace' => true, + 'ignoredDeprecationPaths' => [], + 'exceptionRenderer' => 'App\Error\AppExceptionRenderer', + ], + + /* + * Debugger configuration + * + * Define development error values for Cake\Error\Debugger + * + * - `editor` Set the editor URL format you want to use. + * By default atom, emacs, macvim, phpstorm, sublime, textmate, and vscode are + * available. You can add additional editor link formats using + * `Debugger::addEditor()` during your application bootstrap. + * - `outputMask` A mapping of `key` to `replacement` values that + * `Debugger` should replace in dumped data and logs generated by `Debugger`. + */ + 'Debugger' => [ + 'editor' => 'phpstorm', + ], + + /* + * Email configuration. + * + * By defining transports separately from delivery profiles you can easily + * re-use transport configuration across multiple profiles. + * + * You can specify multiple configurations for production, development and + * testing. + * + * Each transport needs a `className`. Valid options are as follows: + * + * Mail - Send using PHP mail function + * Smtp - Send using SMTP + * Debug - Do not send the email, just return the result + * + * You can add custom transports (or override existing transports) by adding the + * appropriate file to src/Mailer/Transport. Transports should be named + * 'YourTransport.php', where 'Your' is the name of the transport. + */ + 'EmailTransport' => [ + 'default' => [ + 'className' => MailTransport::class, + /* + * The keys host, port, timeout, username, password, client and tls + * are used in SMTP transports + */ + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + /* + * It is recommended to set these options through your environment or app_local.php + */ + //'username' => null, + //'password' => null, + 'client' => null, + 'tls' => false, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], + + /* + * Email delivery profiles + * + * Delivery profiles allow you to predefine various properties about email + * messages from your application and give the settings a name. This saves + * duplication across your application and makes maintenance and development + * easier. Each profile accepts a number of keys. See `Cake\Mailer\Email` + * for more information. + */ + 'Email' => [ + 'default' => [ + 'transport' => 'default', + 'from' => 'you@localhost', + /* + * Will by default be set to config value of App.encoding, if that exists otherwise to UTF-8. + */ + //'charset' => 'utf-8', + //'headerCharset' => 'utf-8', + ], + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * ### Notes + * - Drivers include Mysql Postgres Sqlite Sqlserver + * See vendor\cakephp\cakephp\src\Database\Driver for complete list + * - Do not use periods in database name - it may lead to error. + * See https://github.com/cakephp/cakephp/issues/6471 for details. + * - 'encoding' is recommended to be set to full UTF-8 4-Byte support. + * E.g set it to 'utf8mb4' in MariaDB and MySQL and 'utf8' for any + * other RDBMS. + */ + 'Datasources' => [ + /* + * These configurations should contain permanent settings used + * by all environments. + * + * The values in app_local.php will override any values set here + * and should be used for local and per-environment configurations. + * + * Environment variable based configurations can be loaded here or + * in app_local.php depending on the applications needs. + */ + 'default' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + + /* + * For MariaDB/MySQL the internal default changed from utf8 to utf8mb4, aka full utf-8 support, in CakePHP 3.6 + */ + //'encoding' => 'utf8mb4', + + /* + * If your MySQL server is configured with `skip-character-set-client-handshake` + * then you MUST use the `flags` config to set your charset encoding. + * For e.g. `'flags' => [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']` + */ + 'flags' => [], + 'cacheMetadata' => true, + 'log' => false, + + /* + * Set identifier quoting to true if you are using reserved words or + * special characters in your table or column names. Enabling this + * setting will result in queries built using the Query Builder having + * identifiers quoted when creating SQL. It should be noted that this + * decreases performance because each query needs to be traversed and + * manipulated before being executed. + */ + 'quoteIdentifiers' => true, + + /* + * During development, if using MySQL < 5.6, uncommenting the + * following line could boost the speed at which schema metadata is + * fetched from the database. It can also be set directly with the + * mysql configuration directive 'innodb_stats_on_metadata = 0' + * which is the recommended value in production environments + */ + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], + ], + + 'geo' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + 'encoding' => 'utf8', + 'flags' => [], + 'cacheMetadata' => true, + 'log' => false, + 'quoteIdentifiers' => false, + ], + + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + //'encoding' => 'utf8mb4', + 'flags' => [], + 'cacheMetadata' => true, + 'quoteIdentifiers' => false, + 'log' => false, + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], + ], + ], + + /* + * Configures logging options + */ + 'Log' => [ + 'debug' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'debug', + 'url' => env('LOG_DEBUG_URL', null), + 'scopes' => null, + 'levels' => ['notice', 'info', 'debug'], + ], + 'error' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'error', + 'url' => env('LOG_ERROR_URL', null), + 'scopes' => null, + 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], + ], + // To enable this dedicated query log, you need set your datasource's log flag to true + 'queries' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'queries', + 'url' => env('LOG_QUERIES_URL', null), + 'scopes' => ['cake.database.queries'], + ], + ], + + /* + * Session configuration. + * + * Contains an array of settings to use for session configuration. The + * `defaults` key is used to define a default preset to use for sessions, any + * settings declared here will override the settings of the default config. + * + * ## Options + * + * - `cookie` - The name of the cookie to use. Defaults to value set for `session.name` php.ini config. + * Avoid using `.` in cookie names, as PHP will drop sessions from cookies with `.` in the name. + * - `cookiePath` - The url path for which session cookie is set. Maps to the + * `session.cookie_path` php.ini config. Defaults to base path of app. + * - `timeout` - The time in minutes the session should be valid for. + * Pass 0 to disable checking timeout. + * Please note that php.ini's session.gc_maxlifetime must be equal to or greater + * than the largest Session['timeout'] in all served websites for it to have the + * desired effect. + * - `defaults` - The default configuration set to use as a basis for your session. + * There are four built-in options: php, cake, cache, database. + * - `handler` - Can be used to enable a custom session handler. Expects an + * array with at least the `engine` key, being the name of the Session engine + * class to use for managing the session. CakePHP bundles the `CacheSession` + * and `DatabaseSession` engines. + * - `ini` - An associative array of additional 'session.*` ini values to set. + * + * The built-in `defaults` options are: + * + * - 'php' - Uses settings defined in your php.ini. + * - 'cake' - Saves session files in CakePHP's /tmp directory. + * - 'database' - Uses CakePHP's database sessions. + * - 'cache' - Use the Cache class to save sessions. + * + * To define a custom session handler, save it at src/Http/Session/.php. + * Make sure the class implements PHP's `SessionHandlerInterface` and set + * Session.handler to + * + * To use database sessions, load the SQL file located at config/schema/sessions.sql + */ + 'Session' => [ + 'cookie' => 'JIXEL', + 'defaults' => 'cache', + ], +]; diff --git a/idrocap_wa/config/app_local.example.php b/idrocap_wa/config/app_local.example.php new file mode 100644 index 0000000..8bdb855 --- /dev/null +++ b/idrocap_wa/config/app_local.example.php @@ -0,0 +1,94 @@ + filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT', '__SALT__'), + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * See app.php for more configuration options. + */ + 'Datasources' => [ + 'default' => [ + 'host' => 'localhost', + /* + * CakePHP will use the default DB port based on the driver selected + * MySQL on MAMP uses port 8889, MAMP users will want to uncomment + * the following line and set the port accordingly + */ + //'port' => 'non_standard_port_number', + + 'username' => 'my_app', + 'password' => 'secret', + + 'database' => 'my_app', + /* + * If not using the default 'public' schema with the PostgreSQL driver + * set it here. + */ + //'schema' => 'myapp', + + /* + * You can use a DSN string to set the entire configuration + */ + 'url' => env('DATABASE_URL', null), + ], + + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'host' => 'localhost', + //'port' => 'non_standard_port_number', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + //'schema' => 'myapp', + 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tmp/tests.sqlite'), + ], + ], + + /* + * Email configuration. + * + * Host and credential configuration in case you are using SmtpTransport + * + * See app.php for more configuration options. + */ + 'EmailTransport' => [ + 'default' => [ + 'host' => 'localhost', + 'port' => 25, + 'username' => null, + 'password' => null, + 'client' => null, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], +]; diff --git a/idrocap_wa/config/app_local.php b/idrocap_wa/config/app_local.php new file mode 100644 index 0000000..eb0c81e --- /dev/null +++ b/idrocap_wa/config/app_local.php @@ -0,0 +1,94 @@ + filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT', '1d8f10d21d25f4efea479140b503d0c32a7aac909d93d0a48bb9e153d49a0449'), + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * See app.php for more configuration options. + */ + 'Datasources' => [ + 'default' => [ + 'host' => 'localhost', + /* + * CakePHP will use the default DB port based on the driver selected + * MySQL on MAMP uses port 8889, MAMP users will want to uncomment + * the following line and set the port accordingly + */ + //'port' => 'non_standard_port_number', + + 'username' => 'my_app', + 'password' => 'secret', + + 'database' => 'my_app', + /* + * If not using the default 'public' schema with the PostgreSQL driver + * set it here. + */ + //'schema' => 'myapp', + + /* + * You can use a DSN string to set the entire configuration + */ + 'url' => env('DATABASE_URL', null), + ], + + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'host' => 'localhost', + //'port' => 'non_standard_port_number', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + //'schema' => 'myapp', + 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tmp/tests.sqlite'), + ], + ], + + /* + * Email configuration. + * + * Host and credential configuration in case you are using SmtpTransport + * + * See app.php for more configuration options. + */ + 'EmailTransport' => [ + 'default' => [ + 'host' => 'localhost', + 'port' => 25, + 'username' => null, + 'password' => null, + 'client' => null, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], +]; diff --git a/idrocap_wa/config/bootstrap.php b/idrocap_wa/config/bootstrap.php new file mode 100644 index 0000000..9c0aaaa --- /dev/null +++ b/idrocap_wa/config/bootstrap.php @@ -0,0 +1,231 @@ +parse() +// ->putenv() +// ->toEnv() +// ->toServer(); +// } + +/* + * Read configuration file and inject configuration into various + * CakePHP classes. + * + * By default there is only one configuration file. It is often a good + * idea to create multiple configuration files, and separate the configuration + * that changes from configuration that does not. This makes deployment simpler. + */ +try { + Configure::config('default', new PhpConfig()); + Configure::load('app', 'default', false); +} catch (\Exception $e) { + exit($e->getMessage() . "\n"); +} + +/* + * Load an environment local configuration file to provide overrides to your configuration. + * Notice: For security reasons app_local.php **should not** be included in your git repo. + */ +if (file_exists(CONFIG . 'app_local.php')) { + Configure::load('app_local', 'default'); +} + +/* + * When debug = true the metadata cache should only last + * for a short time. + */ +if (Configure::read('debug')) { + Configure::write('Cache._cake_model_.duration', '+2 minutes'); + Configure::write('Cache._cake_core_.duration', '+2 minutes'); + // disable router cache during development + Configure::write('Cache._cake_routes_.duration', '+2 seconds'); +} + +/* + * Set the default server timezone. Using UTC makes time calculations / conversions easier. + * Check https://php.net/manual/en/timezones.php for list of valid timezone strings. + */ +date_default_timezone_set(Configure::read('App.defaultTimezone')); + +/* + * Configure the mbstring extension to use the correct encoding. + */ +mb_internal_encoding(Configure::read('App.encoding')); + +/* + * Set the default locale. This controls how dates, number and currency is + * formatted and sets the default language to use for translations. + */ +ini_set('intl.default_locale', Configure::read('App.defaultLocale')); + +/* + * Register application error and exception handlers. + */ +(new ErrorTrap(Configure::read('Error')))->register(); +(new ExceptionTrap(Configure::read('Error')))->register(); + +/* + * Include the CLI bootstrap overrides. + */ +if (PHP_SAPI === 'cli') { + require CONFIG . 'bootstrap_cli.php'; +} + +/* + * Set the full base URL. + * This URL is used as the base of all absolute links. + */ +$fullBaseUrl = Configure::read('App.fullBaseUrl'); +if (!$fullBaseUrl) { + /* + * When using proxies or load balancers, SSL/TLS connections might + * get terminated before reaching the server. If you trust the proxy, + * you can enable `$trustProxy` to rely on the `X-Forwarded-Proto` + * header to determine whether to generate URLs using `https`. + * + * See also https://book.cakephp.org/4/en/controllers/request-response.html#trusting-proxy-headers + */ + $trustProxy = false; + + $s = null; + if (env('HTTPS') || ($trustProxy && env('HTTP_X_FORWARDED_PROTO') === 'https')) { + $s = 's'; + } + + $httpHost = env('HTTP_HOST'); + if (isset($httpHost)) { + $fullBaseUrl = 'http' . $s . '://' . $httpHost; + } + unset($httpHost, $s); +} +if ($fullBaseUrl) { + Router::fullBaseUrl($fullBaseUrl); +} +unset($fullBaseUrl); + +Cache::setConfig(Configure::consume('Cache')); +ConnectionManager::setConfig(Configure::consume('Datasources')); +TransportFactory::setConfig(Configure::consume('EmailTransport')); +Mailer::setConfig(Configure::consume('Email')); +Log::setConfig(Configure::consume('Log')); +Security::setSalt(Configure::consume('Security.salt')); + +/* + * Setup detectors for mobile and tablet. + * If you don't use these checks you can safely remove this code + * and the mobiledetect package from composer.json. + */ +ServerRequest::addDetector('mobile', function ($request) { + $detector = new \Detection\MobileDetect(); + + return $detector->isMobile(); +}); +ServerRequest::addDetector('tablet', function ($request) { + $detector = new \Detection\MobileDetect(); + + return $detector->isTablet(); +}); + +/* + * You can enable default locale format parsing by adding calls + * to `useLocaleParser()`. This enables the automatic conversion of + * locale specific date formats. For details see + * @link https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html#parsing-localized-datetime-data + */ +// \Cake\Database\TypeFactory::build('time') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('date') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetime') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestamp') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetimefractional') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestampfractional') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetimetimezone') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestamptimezone') +// ->useLocaleParser(); + +/* + * Custom Inflector rules, can be set to correctly pluralize or singularize + * table, model, controller names or whatever other string is passed to the + * inflection functions. + */ +//Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']); +//Inflector::rules('irregular', ['red' => 'redlings']); +//Inflector::rules('uninflected', ['dontinflectme']); + +// set a custom date and time format +// see https://book.cakephp.org/4/en/core-libraries/time.html#setting-the-default-locale-and-format-string +// and https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax +//\Cake\I18n\FrozenDate::setToStringFormat('dd.MM.yyyy'); +//\Cake\I18n\FrozenTime::setToStringFormat('dd.MM.yyyy HH:mm'); diff --git a/idrocap_wa/config/bootstrap_cli.php b/idrocap_wa/config/bootstrap_cli.php new file mode 100644 index 0000000..fc0dc30 --- /dev/null +++ b/idrocap_wa/config/bootstrap_cli.php @@ -0,0 +1,35 @@ + [ + 'app-name' => '' . Configure::read('Theme.title') . '', + 'app-logo' => Configure::read('Theme.logo'), + + 'small-text' => false, + 'dark-mode' => false, + 'layout-boxed' => false, + + 'header' => [ + 'fixed' => false, + 'border' => true, + 'style' => Header::STYLE_DARK, + 'dropdown-legacy' => false, + ], + + 'sidebar' => [ + 'fixed' => true, + 'collapsed' => false, + 'mini' => true, + 'mini-md' => false, + 'mini-xs' => false, + 'style' => Sidebar::STYLE_DARK_PRIMARY, + + 'flat-style' => false, + 'legacy-style' => false, + 'compact' => false, + 'child-indent' => true, + 'child-hide-collapse' => false, + 'disabled-auto-expand' => false, + ], + + 'footer' => [ + 'fixed' => false, + ], + ], +]; \ No newline at end of file diff --git a/idrocap_wa/config/keys/private.key b/idrocap_wa/config/keys/private.key new file mode 100644 index 0000000..7a309aa --- /dev/null +++ b/idrocap_wa/config/keys/private.key @@ -0,0 +1,52 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKQIBAAKCAgEA0YVnol1T7RaJIiMDiivC1bgDyqn2b31j+t8NQXcLm7dOq8az +Wgsn3ySGj1Was/Mlye5uCegnj9LPOvK6b6wG4NcNKEouAdjwoZ8PFsTZU2q/lGzr +Ze4Kc/E19oVgdKRhTgDuCKq7sShC7Un+2lY0CCt2GSA133Mqoztih5Y+zvlqyKaM +xF6eNy62L1IqNUWEMFIgkVq4Jy2XMii7qrYdE9cJbleZ1MDlTO7a0v3bhLxdC5D6 +2HPcalV3qYKiCWX/EhCz4b8JWfoW8tfV8GoEX+6JV+AohOXC9wdopCV89SJu1x+S +p4yWkBtm1nSMifaPfXqyz9tiGFL8ziJpEW59lTgbd1KZMCcoGIHR8gq7PowDVkAQ +IdU628DS3FPgBgPRV7r9oPuytjPzojmuu64aClgWylE6WDn2daBHUHtlY0NLA7VN +jIMMnvnlM0OBGGN4god4LVzFZkgso36i6RJghYUiKaz7DOQEMEGx6bWQlHxnLR0/ +khv/1ERpKNWq/q0vXeoNA7L1jZ64k3U/MyWmaJPdjcoPFGYI2Vwlz//M1TZmyoV7 +YC01YJcsTbA5+ocukOZDlvsEWZKWJoi/I5vYcQfBZGrAY8pl7LFCVlnpUR+UHB3a +Fp0+Q4OK0OhQuOmbMqz2J/t2MbWXwBsnQkP3XNnoA1t4fbraPeex25NTZVMCAwEA +AQKCAgEAjnRkzQkleeq7nIEv8+7jDsqJkW7UBmO76aNkcOFO/DW7AKId6ZfyKQ69 +ipEKmVU1mUFKgePdmjUb/xlv12OgXZj58i3VcB4fJdRuvu1iUgwfa/xOZMRfSQt0 +xENVHJlzK0UIks36xW35azrHU44O3IsoRdcXqfC0yb0jtcpatADzMK/Ev/MRIbXZ +2vzDg+rbALumNw32bXTa+xik2GHwDUBEwkg/aF8qyI8SKyi861fi721IkIjeEVJB +BPiz0S4PKio/E7r+0bVvivdjF44NoWge66eWBR3u3GSmKgzvFACwWgW2gcLdz+dB +mYgu0dLZJtiY4ShpXt510nWk+Fwmd2YHSt0U/rnoiOSEXRqh2UPZL9zgK0F81E8v +Ay1Yij59P0tkjIz3VtYluMGV6nXoQunJyIFsUN3r3h2p6ZxeitN+CEmUN/zOvmrN +Ziqy4Hnta03eC3ZZ3i3NIHuth63hVrh5qFEKT5Ggqvw6Swfzg1mL9biZ+4A1xICP +8850+yBaX6n3BgRwLmFd9xjtA7GNJ1vrcOn6+uw7OOaUl+WUlnX8uqDCPE/mhMd4 +SM/O4kL/G4BFb45q4LeYkiuFk5UHatWdcOlttQkvrgSCH4PpfJDiilKn/tVU34HY +OM7/N+j9wMpZj7dqPMra+WbzKA4I0d+rnKZsUVHbCAZZzEf0w/kCggEBAPRQKV8W +w1Z+JlZeRtoxSSCSEgHDpun13ZiXBi17ErYhN5LTCMJ8XUmeeexVCcRMOqjvClgz +2hrHaC66nW2pfBu2euVHqecD0likKEINsucbTa2PNZeP0sV8px1k5NASRlNilqGy +vrWT425E7yrss2RBOcE6ro6M9QYZSLZjiYNqzk6w4j6McyFertq7/Yz9JCaAq72e +ptCrvzoAtCFra3nwTgxlu1QVB8I/Kjg94lpTLQcS7mehDep+qYSlnFzJ5CnGF7t4 +K5WZ4VEo1u4dpbewTVDfc3W+ODTQgmYByU6mUwl4Kf4V6ovKJ9say1z0ZdbXcHRJ +ZG8+Hdld47TwHe8CggEBANuLLtsoCvUyLs9X6+6kToSTN3FVRnkfoJLbXe9+smw/ +5QAvvh2lwlwc6xXajEEsNK8z9mVRSCrXoiqRTjTo2ioe0oxx9Gnou+/d2MB9WJm3 +hQAwMGjwifg6AD9bZre+NiEl92WmlJs3fm4zFrEMpCBCOJ7JIe7GxsdKwR/guvQt +9k/NCQj2fOnCzCoFYtebPPDXukcn2Ad2XOkvLWzLmG4HRGuLPeqgjvxppBdtU3Xm +NJklIndw1g+xcY8/7bbNyo8Nd/PV/ymv/sflrQyXjVs4mwwAgY9usFntO+qT4nEd +wfPgedDlpsNDprSdjDo5xNA79yaVFUuzJCIDFXO9Ut0CggEAaA5QYKCoWAlouLZ0 +xO/i7o1oP/od+F3woNIKHorhwFLLgayCeZtQfE+ULFVX0JSLE3KkXEbRaUBvHh/7 +dz6NjpwdIdRxB+S3zWs1flSpUwdtATQSplfqdJSP9NQJJJnz/AXslDg2Q84WOtv/ +Za/lBBlHyQX+XNaqcYuJTa19X0y5TAjIg818J8VVAfK5njgfEosRGrUc5ZmQ29p6 +3hULdKcmBt+5dqlyYYhXqhapdsEgV3f3tImDDNIfz1BeFaMjm6s0ZnNbVN9yeQfE +6ywTbfYYKA7T9V0sQUphj6LJI8dxbIISmJarDBjw+sAhx5iMW4Hs8opjzYGOYws7 +NdBjXwKCAQBc0Bh8+g633gFAEtFhUAEJtxsHRJ/IcQB3VVn+97cCYHi1fXmIGx1x +x5/y2zPUEZYsQ3F1H8m8ovChwlAnuhERIXqteTd01rktDMKnjdY5FgaaL8UneBk7 +4XldT4y7PSSxGtXeGXBVtj4y5FJBgzCXmqdJKYq44TwD4KyIh39B33R0BCA/s8TX +Jk0drq08rRo0T18m2cdQUE+zHQi9J81HJrdcJ7+DQ2FvgFGovcU84Jd37uUFTaSR +ediiUMp0L8fkdjMx2FRJEWhKpeRkoGVYHTQe/M/JDWhsfAiKgP6IB6aJLWsSTyQT +BLSjQr+XlfiId/FiVEBugktSPa+CAJXZAoIBAQDj32TA+MI5gWtWlP4u9KsyrDGD +NJyutrAGziQSibgj5CW++fVm6TcXZ3rezxFZ/QDr8MlEJhpGoi3Ca+U0JyIcrn3z +fgwKGJd7kVFD8jhqm85j8rMk9sqEgg88cE6yt4tC+LAwLLeyhVqea5q5vF5dV9gN +1LtP6E30MQxWRBWhcp7FyZEzS6eYIjQwVCaVD2tDXg3hQQ/gxyPantsEdgoqCfgu +MjBJiaw5fO+qBROzema0LDXs7m5HAZRur22c9a45d0+SmCAmudsxoKrnV6w7gdd+ +1Jp1KFef7gx9iSBm3E3rcCBBOfPfRKbvBD5bhNXxT/a/iK8wPQY4uKiwgKt+ +-----END RSA PRIVATE KEY----- + diff --git a/idrocap_wa/config/keys/public.key b/idrocap_wa/config/keys/public.key new file mode 100644 index 0000000..fc7f1a9 --- /dev/null +++ b/idrocap_wa/config/keys/public.key @@ -0,0 +1,15 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0YVnol1T7RaJIiMDiivC +1bgDyqn2b31j+t8NQXcLm7dOq8azWgsn3ySGj1Was/Mlye5uCegnj9LPOvK6b6wG +4NcNKEouAdjwoZ8PFsTZU2q/lGzrZe4Kc/E19oVgdKRhTgDuCKq7sShC7Un+2lY0 +CCt2GSA133Mqoztih5Y+zvlqyKaMxF6eNy62L1IqNUWEMFIgkVq4Jy2XMii7qrYd +E9cJbleZ1MDlTO7a0v3bhLxdC5D62HPcalV3qYKiCWX/EhCz4b8JWfoW8tfV8GoE +X+6JV+AohOXC9wdopCV89SJu1x+Sp4yWkBtm1nSMifaPfXqyz9tiGFL8ziJpEW59 +lTgbd1KZMCcoGIHR8gq7PowDVkAQIdU628DS3FPgBgPRV7r9oPuytjPzojmuu64a +ClgWylE6WDn2daBHUHtlY0NLA7VNjIMMnvnlM0OBGGN4god4LVzFZkgso36i6RJg +hYUiKaz7DOQEMEGx6bWQlHxnLR0/khv/1ERpKNWq/q0vXeoNA7L1jZ64k3U/MyWm +aJPdjcoPFGYI2Vwlz//M1TZmyoV7YC01YJcsTbA5+ocukOZDlvsEWZKWJoi/I5vY +cQfBZGrAY8pl7LFCVlnpUR+UHB3aFp0+Q4OK0OhQuOmbMqz2J/t2MbWXwBsnQkP3 +XNnoA1t4fbraPeex25NTZVMCAwEAAQ== +-----END PUBLIC KEY----- + diff --git a/idrocap_wa/config/paths.php b/idrocap_wa/config/paths.php new file mode 100644 index 0000000..fcd260d --- /dev/null +++ b/idrocap_wa/config/paths.php @@ -0,0 +1,94 @@ + [ + 'onlyDebug' => true, + ], + 'Bake' => [ + 'onlyCli' => true, + 'optional' => true, + ], + 'Migrations' => [ + 'onlyCli' => true, + ], + 'CakeLte' => [], +]; diff --git a/idrocap_wa/config/routes.php b/idrocap_wa/config/routes.php new file mode 100644 index 0000000..a7f36a7 --- /dev/null +++ b/idrocap_wa/config/routes.php @@ -0,0 +1,357 @@ +setRouteClass(InflectedRoute::class); + + $routes->prefix('Api', function (RouteBuilder $routes) { + $routes->setExtensions(['json', 'csv']); + + $routes->resources('Attachments', [ + 'id' => '.*', + ]); + + $routes->resources('Notifications', [ + 'map' => [ + '' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'index' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'count' => [ + 'action' => 'count', + 'method' => ['GET'], + ], + 'edit/{id}' => [ + 'action' => 'edit', + 'method' => ['POST'], + ], + 'check' => [ + 'action' => 'check', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('Organisations', [ + 'connectOptions' => [ + 'photo' => '.*', + 'pass' => ['id', 'photo'], + ], + 'map' => [ + 'get_photo/{photo}' => [ + 'action' => 'getPhoto', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('OrganisationTypes', ['inflect' => 'underscore']); + + $routes->resources('Users', [ + 'connectOptions' => [ + 'photo' => '.*', + 'pass' => ['id', 'photo'], + ], + 'map' => [ + 'login' => [ + 'action' => 'login', + 'method' => ['POST', 'GET'], + ], + 'get_photo/{photo}' => [ + 'action' => 'getPhoto', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('Subscriptions', [ + 'map' => [ + 'subscribe' => [ + 'action' => 'subscribe', + 'method' => ['POST'], + ], + 'unsubscribe' => [ + 'action' => 'unsubscribe', + 'method' => ['DELETE'], + ], + ], + ]); + + $routes->resources('WaterDrawingPaperworks', [ + 'inflect' => 'underscore', + 'map' => [ + '' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'index' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'view/{id}' => [ + 'action' => 'view', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('WaterDrawingDerivations', [ + 'inflect' => 'underscore', + 'map' => [ + 'update_data' => [ + 'action' => 'update_data', + 'method' => ['POST'], + ], + 'update_location' => [ + 'action' => 'update_location', + 'method' => ['POST'], + ], + 'view/{id}' => [ + 'action' => 'view', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('WaterDrawingMeasurements', [ + 'inflect' => 'underscore', + 'map' => [ + 'add' => [ + 'action' => 'add', + 'method' => ['POST'], + ], + 'last_index/{id}' => [ + 'action' => 'last_index', + 'method' => ['GET'], + ], + ], + ]); + }); + + $routes->scope('/', function (RouteBuilder $builder) { + $builder->setExtensions(['json', 'csv']); + + $builder->connect('/', ['controller' => 'Dashboard', 'action' => 'index']); + + $builder->connect('/attachments/view/{id}', ['controller' => 'Attachments', 'action' => 'view'])->setPass(['id']); + $builder->connect('/attachments/markAsRelevant/{id}', ['controller' => 'Attachments', 'action' => 'markAsRelevant'])->setPass(['id']); + $builder->connect('/attachments/markAsDeleted/{id}', ['controller' => 'Attachments', 'action' => 'markAsDeleted'])->setPass(['id']); + + $builder->connect('/capabilities', ['controller' => 'Capabilities', 'action' => 'index']); + $builder->connect('/capabilities/index', ['controller' => 'Capabilities', 'action' => 'index']); + $builder->connect('/capabilities/hide/{id}', ['controller' => 'Capabilities', 'action' => 'hide'])->setPass(['id']); + $builder->connect('/capabilities/show/{id}', ['controller' => 'Capabilities', 'action' => 'show'])->setPass(['id']); + $builder->connect('/capabilities/delete/{id}', ['controller' => 'Capabilities', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/capabilities/restore/{id}', ['controller' => 'Capabilities', 'action' => 'restore'])->setPass(['id']); + + $builder->connect('/controllable_objects/getAttachments/{id}', ['controller' => 'ControllableObjects', 'action' => 'getAttachments'])->setPass(['id']); + + $builder->connect('/deliveries/{id}', ['controller' => 'Deliveries', 'action' => 'index'])->setPass(['id']); + $builder->connect('/deliveries/index/{id}', ['controller' => 'Deliveries', 'action' => 'index'])->setPass(['id']); + $builder->connect('/deliveries/delete/{id}', ['controller' => 'Deliveries', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/emails/add/{id}', ['controller' => 'Emails', 'action' => 'add'])->setPass(['id']); + $builder->connect('/emails/edit/{id}', ['controller' => 'Emails', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/faxes/add/{id}', ['controller' => 'Faxes', 'action' => 'add'])->setPass(['id']); + $builder->connect('/faxes/edit/{id}', ['controller' => 'Faxes', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/filters/getFilterInput/{id}', ['controller' => 'Filters', 'action' => 'getFilterInput'])->setPass(['id']); + + $builder->connect('/groups', ['controller' => 'Groups', 'action' => 'index']); + $builder->connect('/groups/index', ['controller' => 'Groups', 'action' => 'index']); + $builder->connect('/groups/add', ['controller' => 'Groups', 'action' => 'add']); + $builder->connect('/groups/view/{id}', ['controller' => 'Groups', 'action' => 'view'])->setPass(['id']); + $builder->connect('/groups/edit/{id}', ['controller' => 'Groups', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/groups/delete/{id}', ['controller' => 'Groups', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/groups/handleCapabilities/{id}', ['controller' => 'Groups', 'action' => 'handleCapabilities'])->setPass(['id']); + + $builder->connect('/maps', ['controller' => 'Maps', 'action' => 'index']); + $builder->connect('/maps/index', ['controller' => 'Maps', 'action' => 'index']); + $builder->connect('/maps/getWfs', ['controller' => 'Maps', 'action' => 'getWfs']); + $builder->connect('/maps/geocode', ['controller' => 'Maps', 'action' => 'geocode']); + + $builder->connect('/mobile_phones/add/{id}', ['controller' => 'MobilePhones', 'action' => 'add'])->setPass(['id']); + $builder->connect('/mobile_phones/edit/{id}', ['controller' => 'MobilePhones', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/notifications', ['controller' => 'Notifications', 'action' => 'index']); + $builder->connect('/notifications/index', ['controller' => 'Notifications', 'action' => 'index']); + $builder->connect('/notifications/readAll', ['controller' => 'Notifications', 'action' => 'readAll']); + $builder->connect('/notifications/testAll', ['controller' => 'Notifications', 'action' => 'testAll']); + $builder->connect('/notifications/view/{id}', ['controller' => 'Notifications', 'action' => 'view'])->setPass(['id']); + + $builder->connect('/organisations', ['controller' => 'Organisations', 'action' => 'index']); + $builder->connect('/organisations/index', ['controller' => 'Organisations', 'action' => 'index']); + $builder->connect('/organisations/add', ['controller' => 'Organisations', 'action' => 'add']); + $builder->connect('/organisations/view/{id}', ['controller' => 'Organisations', 'action' => 'view'])->setPass(['id']); + $builder->connect('/organisations/edit/{id}', ['controller' => 'Organisations', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/organisations/delete/{id}', ['controller' => 'Organisations', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/phones/add/{id}', ['controller' => 'Phones', 'action' => 'add'])->setPass(['id']); + $builder->connect('/phones/edit/{id}', ['controller' => 'Phones', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/telegram_chats/add/{id}', ['controller' => 'TelegramChats', 'action' => 'add'])->setPass(['id']); + $builder->connect('/telegram_chats/edit/{id}', ['controller' => 'TelegramChats', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/users', ['controller' => 'Users', 'action' => 'index']); + $builder->connect('/users/login_oidc', ['controller' => 'Users', 'action' => 'login_oidc']); + $builder->connect('/users/login_oidc_authenticated', ['controller' => 'Users', 'action' => 'login_oidc_authenticated']); + $builder->connect('/users/index', ['controller' => 'Users', 'action' => 'index']); + $builder->connect('/users/add', ['controller' => 'Users', 'action' => 'add']); + $builder->connect('/users/view/{id}', ['controller' => 'Users', 'action' => 'view'])->setPass(['id']); + $builder->connect('/users/edit/{id}', ['controller' => 'Users', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/users/delete/{id}', ['controller' => 'Users', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/users/login', ['controller' => 'Users', 'action' => 'login']); + $builder->connect('/users/logout', ['controller' => 'Users', 'action' => 'logout']); + $builder->connect('/users/passwordRecovery', ['controller' => 'Users', 'action' => 'passwordRecovery']); + $builder->connect('/users/chooseNewPassword/{id}', ['controller' => 'Users', 'action' => 'chooseNewPassword'])->setPass(['id']); + $builder->connect('/users/oneTimePassword/{otp}', ['controller' => 'Users', 'action' => 'oneTimePassword'])->setPass(['otp']); + $builder->connect('/users/getPhoto/{id}', ['controller' => 'Users', 'action' => 'getPhoto'])->setPass(['id']); + $builder->connect('/users/deleteUserPhoto/{id}', ['controller' => 'Users', 'action' => 'deleteUserPhoto'])->setPass(['id']); + $builder->connect('/users/add-citizen', ['controller' => 'Users', 'action' => 'add_citizen']); + $builder->connect('/users/verify-citizen/{token}', ['controller' => 'Users', 'action' => 'verify_citizen'])->setPass(['token']); + + $builder->connect('/water_drawing_paperworks', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index']); + $builder->connect('/water_drawing_paperworks/index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index']); + $builder->connect('/water_drawing_paperworks/index_snapshots/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_paperworks/index_snapshots_all', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all']); + $builder->connect('/water_drawing_paperworks/validate_index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate_index']); + $builder->connect('/water_drawing_paperworks/add_scan', ['controller' => 'WaterDrawingPaperworks', 'action' => 'add_scan']); + $builder->connect('/water_drawing_paperworks/add', ['controller' => 'WaterDrawingPaperworks', 'action' => 'add']); + $builder->connect('/water_drawing_paperworks/view_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/view/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/view_scan_snapshot/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan_snapshot'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/view_snapshot/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_snapshot'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/edit_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'edit_scan'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/edit/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/delete/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/validate_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate_scan'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/validate/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/send_to_drar/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_drar'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/send_to_gc/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_gc'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/submit_antimafia_request/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'submit_antimafia_request'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/antimafia_request_to_anac/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'antimafia_request_to_anac'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/request_self_certification/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'request_self_certification'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/applicants_water_drawing_paperworks_item_block/{id}/{status_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'applicants_water_drawing_paperworks_item_block'])->setPass(['id', 'status_id']); + $builder->connect('/water_drawing_paperworks/applicants_water_drawing_paperworks_item_block/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'applicants_water_drawing_paperworks_item_block'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/intended_uses_water_drawing_paperworks_item_block/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'intended_uses_water_drawing_paperworks_item_block'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/upload_attachment/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_attachment'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/upload_attachment_scan/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_attachment_scan'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/upload_antimafia_attachment/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_antimafia_attachment'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/assign/{id}/{organisation_type_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign'])->setPass(['id', 'organisation_type_id']); + $builder->connect('/water_drawing_paperworks/citizen_submission_index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index']); + $builder->connect('/water_drawing_paperworks/citizen_documentation_index/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/citizen_documentation_requested/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_requested'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/citizen_upload_attachment/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_upload_attachment'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/citizen_submit_paperwork/{applicant_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submit_paperwork'])->setPass(['applicant_id']); + $builder->connect('/water_drawing_paperworks/citizen_request_paperwork', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_request_paperwork']); + $builder->connect('/water_drawing_paperworks/citizen_send_to_validation/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_send_to_validation'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/delete_attachment/{id}/{attachment_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'delete_attachment'])->setPass(['id', 'attachment_id']); + $builder->connect('/water_drawing_paperworks/send_to_validation/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_validation'])->setPass(['id']); + + $builder->connect('/applicants/search_applicants', ['controller' => 'Applicants', 'action' => 'search_applicants']); + $builder->connect('/applicants/get_applicant/{id}', ['controller' => 'Applicants', 'action' => 'get_applicant'])->setPass(['id']); + $builder->connect('/applicants/edit/{id}', ['controller' => 'Applicants', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/applicants/edit/{id}/{water_id}', ['controller' => 'Applicants', 'action' => 'edit'])->setPass(['id','water_id']); + $builder->connect('/applicants/view/{id}/', ['controller' => 'Applicants', 'action' => 'view'])->setPass(['id']); + $builder->connect('/applicants/citizen_add/', ['controller' => 'Applicants', 'action' => 'citizen_add']); + $builder->connect('/applicants/citizen_edit/{id}', ['controller' => 'Applicants', 'action' => 'citizen_edit'])->setPass(['id']); + $builder->connect('/applicants/citizen_view', ['controller' => 'Applicants', 'action' => 'citizen_view']); + + $builder->connect('/water_drawing_measurements/add/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeasurements', 'action' => 'add'])->setPass(['water_drawing_meter_id']); + $builder->connect('/water_drawing_measurements/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingMeasurements', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + + $builder->connect('/water_drawing_meters/add/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'add'])->setPass(['water_drawing_derivation_id']); + $builder->connect('/water_drawing_meters/edit/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'edit'])->setPass(['water_drawing_meter_id']); + $builder->connect('/water_drawing_meters/view/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'view'])->setPass(['water_drawing_meter_id']); + $builder->connect('/water_drawing_meters/dismiss/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss'])->setPass(['water_drawing_meter_id']); + + $builder->connect('/water_drawing_payments/index_all', ['controller' => 'WaterDrawingPayments', 'action' => 'index_all']); + $builder->connect('/water_drawing_payments/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_payments/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_payments/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_payments/edit/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_payments/view/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_payments/delete/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/water_drawing_derivations/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_derivations/view/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'view'])->setPass(['water_drawing_derivation_id']); + $builder->connect('/water_drawing_derivations/edit/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'edit'])->setPass(['water_drawing_derivation_id']); + $builder->connect('/water_drawing_derivations/delete/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'delete'])->setPass(['water_drawing_derivation_id']); + + $builder->connect('/water_drawing_return_points/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_return_points/view/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_return_points/edit/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_return_points/delete/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/water_drawing_articles/', ['controller' => 'WaterDrawingArticles', 'action' => 'index']); + $builder->connect('/water_drawing_articles/add', ['controller' => 'WaterDrawingArticles', 'action' => 'add']); + $builder->connect('/water_drawing_articles/edit/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_articles/view/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_articles/delete/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/water_drawing_articles/change_status/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'change_status'])->setPass(['id']); + + $builder->connect('/water_drawing_fees/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingFees', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_fees/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingFees', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_fees/view/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_fees/edit/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_fees/delete/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/water_drawing_paperwork_pecs/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_paperwork_pecs/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_paperwork_pecs/edit/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_paperwork_pecs/view/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_paperwork_pecs/delete/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/ai_services/autocomplete', ['controller' => 'AiServices', 'action' => 'autocomplete']); + $builder->connect('/pecs/add/{id}', ['controller' => 'Pecs', 'action' => 'add'])->setPass(['id']); + $builder->connect('/pecs/edit/{id}', ['controller' => 'Pecs', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/privacy/edit/', ['controller' => 'Privacy', 'action' => 'edit']); + $builder->connect('/privacy/view', ['controller' => 'Privacy', 'action' => 'view']); + $builder->connect('/privacy/view_public', ['controller' => 'Privacy', 'action' => 'view_public']); + $builder->connect('/privacy/accept_privacy', ['controller' => 'Privacy', 'action' => 'accept_privacy']); + + $builder->connect('/districts/search_districts', ['controller' => 'Districts', 'action' => 'search_districts']); + $builder->connect('/water_drawing_paperworks/citizen_upload_payment_receipt/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_upload_payment_receipt'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/index_csv', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_csv']); + $builder->connect('/water_drawing_paperworks/index_snapshots_all_csv', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all_csv']); + $builder->connect('/water_drawing_paperworks/index_snapshots_csv/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_csv'])->setPass(['id']); + + $builder->connect('/tags', ['controller' => 'Tags', 'action' => 'index']); + $builder->connect('/tags/index', ['controller' => 'Tags', 'action' => 'index']); + $builder->connect('/tags/add', ['controller' => 'Tags', 'action' => 'add']); + $builder->connect('/tags/view', ['controller' => 'Tags', 'action' => 'view']); + $builder->connect('/tags/view/{id}', ['controller' => 'Tags', 'action' => 'view'])->setPass(['id']); + $builder->connect('/tags/edit', ['controller' => 'Tags', 'action' => 'edit']); + $builder->connect('/tags/edit/{id}', ['controller' => 'Tags', 'action' => 'edit'])->setPass(['id']); + + }); +}; diff --git a/idrocap_wa/config/schema/i18n.sql b/idrocap_wa/config/schema/i18n.sql new file mode 100644 index 0000000..e59d1e6 --- /dev/null +++ b/idrocap_wa/config/schema/i18n.sql @@ -0,0 +1,18 @@ +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# MIT License (https://opensource.org/licenses/mit-license.php) + +CREATE TABLE i18n ( + id int NOT NULL auto_increment, + locale varchar(6) NOT NULL, + model varchar(255) NOT NULL, + foreign_key int(10) NOT NULL, + field varchar(255) NOT NULL, + content text, + PRIMARY KEY (id), + UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field), + INDEX I18N_FIELD(model, foreign_key, field) +); diff --git a/idrocap_wa/config/schema/sessions.sql b/idrocap_wa/config/schema/sessions.sql new file mode 100644 index 0000000..1aa0a0f --- /dev/null +++ b/idrocap_wa/config/schema/sessions.sql @@ -0,0 +1,15 @@ +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# MIT License (https://opensource.org/licenses/mit-license.php) + +CREATE TABLE `sessions` ( + `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ + `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ + `data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob + `expires` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/idrocap_wa/dockerfiles/cake b/idrocap_wa/dockerfiles/cake new file mode 100755 index 0000000..bffbd99 --- /dev/null +++ b/idrocap_wa/dockerfiles/cake @@ -0,0 +1,152 @@ +#!/usr/bin/env sh + +if [ -f /run/secrets/sentry_dsn ]; then + export SENTRY_DSN=$(cat /run/secrets/sentry_dsn) +else + echo "Secret file 'sentry_dsn' not found!" >&2 +fi +if [ -f /run/secrets/oidc_client_id ]; then + export OIDC_CLIENT_ID=$(cat /run/secrets/oidc_client_id) +else + echo "Secret file 'oidc_client_id' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_username ]; then + export GEOSERVER_USERNAME=$(cat /run/secrets/geoserver_username) +else + echo "Secret file 'geoserver_username' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_password ]; then + export GEOSERVER_PASSWORD=$(cat /run/secrets/geoserver_password) +else + echo "Secret file 'geoserver_password' not found!" >&2 +fi +if [ -f /run/secrets/minio_access_key ]; then + export MINIO_ACCESS_KEY=$(cat /run/secrets/minio_access_key) +else + echo "Secret file 'minio_access_key' not found!" >&2 +fi +if [ -f /run/secrets/minio_secret_key ]; then + export MINIO_SECRET_KEY=$(cat /run/secrets/minio_secret_key) +else + echo "Secret file 'minio_secret_key' not found!" >&2 +fi +if [ -f /run/secrets/telegram_bot_token ]; then + export TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram_bot_token) +else + echo "Secret file 'telegram_bot_token' not found!" >&2 +fi +if [ -f /run/secrets/security_jwuc ]; then + export SECURITY_JWUC=$(cat /run/secrets/security_jwuc) +else + echo "Secret file 'security_jwuc' not found!" >&2 +fi +if [ -f /run/secrets/security_jwac ]; then + export SECURITY_JWAC=$(cat /run/secrets/security_jwac) +else + echo "Secret file 'security_jwac' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_username ]; then + export MYSQL_JIXEL_USERNAME=$(cat /run/secrets/mysql_jixel_username) +else + echo "Secret file 'mysql_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_password ]; then + export MYSQL_JIXEL_PASSWORD=$(cat /run/secrets/mysql_jixel_password) +else + echo "Secret file 'mysql_jixel_password' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_username ]; then + export MYSQL_GEO_JIXEL_USERNAME=$(cat /run/secrets/mysql_geo_jixel_username) +else + echo "Secret file 'mysql_geo_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_password ]; then + export MYSQL_GEO_JIXEL_PASSWORD=$(cat /run/secrets/mysql_geo_jixel_password) +else + echo "Secret file 'mysql_geo_jixel_password' not found!" >&2 +fi + +################################################################################ +# +# Cake is a shell script for invoking CakePHP shell commands +# +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project +# @since 1.2.0 +# @license https://opensource.org/licenses/mit-license.php MIT License +# +################################################################################ + +# Canonicalize by following every symlink of the given name recursively +canonicalize() { + NAME="$1" + if [ -f "$NAME" ] + then + DIR=$(dirname -- "$NAME") + NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") + fi + while [ -h "$NAME" ]; do + DIR=$(dirname -- "$NAME") + SYM=$(readlink "$NAME") + NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") + done + echo "$NAME" +} + +# Find a CLI version of PHP +findCliPhp() { + for TESTEXEC in php php-cli /usr/local/bin/php + do + SAPI=$(echo "" | $TESTEXEC 2>/dev/null) + if [ "$SAPI" = "cli" ] + then + echo $TESTEXEC + return + fi + done + echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 + echo "php"; +} + +# If current path is a symlink, resolve to real path +realname="$0" +if [ -L "$realname" ] +then + realname=$(readlink -f "$0") +fi + +CONSOLE=$(dirname -- "$(canonicalize "$realname")") +APP=$(dirname "$CONSOLE") + +# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment +# variable with the correct path in it. +if [ -z "$PHP" ] +then + PHP=$(findCliPhp) +fi + +if [ "$(basename "$realname")" != 'cake' ] +then + exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" +else + exec "$PHP" "$CONSOLE"/cake.php "$@" +fi + +exit diff --git a/idrocap_wa/dockerfiles/run b/idrocap_wa/dockerfiles/run new file mode 100755 index 0000000..b5e4d8a --- /dev/null +++ b/idrocap_wa/dockerfiles/run @@ -0,0 +1,93 @@ +#!/bin/bash + +httpd_user=${httpd_user:-apache} +httpd_uid=${httpd_uid:-48} +httpd_group=${httpd_group:-apache} + +useradd -u $httpd_uid -s /sbin/nologin $httpd_user + +export httpd_user +export httpd_group + +if [ -f /run/secrets/sentry_dsn ]; then + export SENTRY_DSN=$(cat /run/secrets/sentry_dsn) +else + echo "Secret file 'sentry_dsn' not found!" >&2 +fi +if [ -f /run/secrets/oidc_client_id ]; then + export OIDC_CLIENT_ID=$(cat /run/secrets/oidc_client_id) +else + echo "Secret file 'oidc_client_id' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_username ]; then + export GEOSERVER_USERNAME=$(cat /run/secrets/geoserver_username) +else + echo "Secret file 'geoserver_username' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_password ]; then + export GEOSERVER_PASSWORD=$(cat /run/secrets/geoserver_password) +else + echo "Secret file 'geoserver_password' not found!" >&2 +fi +if [ -f /run/secrets/minio_access_key ]; then + export MINIO_ACCESS_KEY=$(cat /run/secrets/minio_access_key) +else + echo "Secret file 'minio_access_key' not found!" >&2 +fi +if [ -f /run/secrets/minio_secret_key ]; then + export MINIO_SECRET_KEY=$(cat /run/secrets/minio_secret_key) +else + echo "Secret file 'minio_secret_key' not found!" >&2 +fi +if [ -f /run/secrets/telegram_bot_token ]; then + export TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram_bot_token) +else + echo "Secret file 'telegram_bot_token' not found!" >&2 +fi +if [ -f /run/secrets/security_jwuc ]; then + export SECURITY_JWUC=$(cat /run/secrets/security_jwuc) +else + echo "Secret file 'security_jwuc' not found!" >&2 +fi +if [ -f /run/secrets/security_jwac ]; then + export SECURITY_JWAC=$(cat /run/secrets/security_jwac) +else + echo "Secret file 'security_jwac' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_username ]; then + export MYSQL_JIXEL_USERNAME=$(cat /run/secrets/mysql_jixel_username) +else + echo "Secret file 'mysql_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_password ]; then + export MYSQL_JIXEL_PASSWORD=$(cat /run/secrets/mysql_jixel_password) +else + echo "Secret file 'mysql_jixel_password' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_username ]; then + export MYSQL_GEO_JIXEL_USERNAME=$(cat /run/secrets/mysql_geo_jixel_username) +else + echo "Secret file 'mysql_geo_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_password ]; then + export MYSQL_GEO_JIXEL_PASSWORD=$(cat /run/secrets/mysql_geo_jixel_password) +else + echo "Secret file 'mysql_geo_jixel_password' not found!" >&2 +fi + +chmod -R o+w /var/www/jixel/tmp/ +chmod -R o+w /var/www/jixel/logs/ + +/usr/sbin/php-fpm +chown -R $httpd_user:$httpd_group /run/php-fpm +/usr/sbin/httpd -DFOREGROUND diff --git a/idrocap_wa/dockerfiles/www.conf b/idrocap_wa/dockerfiles/www.conf new file mode 100644 index 0000000..ddc8904 --- /dev/null +++ b/idrocap_wa/dockerfiles/www.conf @@ -0,0 +1,453 @@ +; Start a new pool named 'www'. +; the variable $pool can be used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Per pool prefix +; It only applies on the following directives: +; - 'access.log' +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or @php_fpm_prefix@) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +; RPM: apache user chosen to provide access to the same directories as httpd +user = apache +; RPM: Keep a group allowed to write in log dir. +group = apache + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on +; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses +; (IPv6 and IPv4-mapped) on a specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /run/php-fpm/www.sock + +; Set listen(2) backlog. +; Default Value: 511 +;listen.backlog = 511 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. +; Default Values: user and group are set as the running user +; mode is set to 0660 +;listen.owner = nobody +;listen.group = nobody +;listen.mode = 0660 + +; When POSIX Access Control Lists are supported you can set them using +; these options, value is a comma separated list of user/group names. +; When set, listen.owner and listen.group are ignored +listen.acl_users = apache,nginx +;listen.acl_groups = + +; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +listen.allowed_clients = 127.0.0.1 + +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + +; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user +; or group is differrent than the master process user. It allows to create process +; core dump and ptrace the process for the pool user. +; Default Value: no +; process.dumpable = yes + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 50 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 5 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 5 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 35 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +;pm.max_requests = 500 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. It shows the following informations: +; pool - the name of the pool; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. +; Example output: +; pool: www +; process manager: static +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; +; By default the status page output is formatted as text/plain. Passing either +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: @EXPANDED_DATADIR@/fpm/status.html +; +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;pm.status_path = /status + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;ping.path = /ping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +;ping.response = pong + +; The access log file +; Default: not set +;access.log = log/$pool.access.log + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: output header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +slowlog = /var/log/php-fpm/www-slow.log + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; Depth of slow log stack trace. +; Default Value: 20 +;request_slowlog_trace_depth = 20 + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_terminate_timeout = 0 + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +;chdir = /var/www + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Clear environment in FPM workers +; Prevents arbitrary environment variables from reaching FPM worker processes +; by clearing the environment in workers before env vars specified in this +; pool configuration are added. +; Setting to "no" will make all environment variables available to PHP code +; via getenv(), $_ENV and $_SERVER. +; Default Value: yes +; clear_env = no + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; execute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 .php7 + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp +env[SENTRY_DSN] = "${SENTRY_DSN}" +env[OIDC_CLIENT_ID] = "${OIDC_CLIENT_ID}" +env[RABBITMQ_USERNAME] = "${RABBITMQ_USERNAME}" +env[RABBITMQ_PASSWORD] = "${RABBITMQ_PASSWORD}" +env[GEOSERVER_USERNAME] = "${GEOSERVER_USERNAME}" +env[GEOSERVER_PASSWORD] = "${GEOSERVER_PASSWORD}" +env[MINIO_ACCESS_KEY] = "${MINIO_ACCESS_KEY}" +env[MINIO_SECRET_KEY] = "${MINIO_SECRET_KEY}" +env[TELEGRAM_BOT_TOKEN] = "${TELEGRAM_BOT_TOKEN}" +env[SECURITY_JWUC] = "${SECURITY_JWUC}" +env[SECURITY_JWAC] = "${SECURITY_JWAC}" +env[MYSQL_JIXEL_USERNAME] = "${MYSQL_JIXEL_USERNAME}" +env[MYSQL_JIXEL_PASSWORD] = "${MYSQL_JIXEL_PASSWORD}" +env[MYSQL_GEO_JIXEL_USERNAME] = "${MYSQL_GEO_JIXEL_USERNAME}" +env[MYSQL_GEO_JIXEL_PASSWORD] = "${MYSQL_GEO_JIXEL_PASSWORD}" + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or @prefix@) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +php_admin_value[error_log] = /var/log/php-fpm/www-error.log +php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 128M + +; Set the following data paths to directories owned by the FPM process user. +; +; Do not change the ownership of existing system directories, if the process +; user does not have write permission, create dedicated directories for this +; purpose. +; +; See warning about choosing the location of these directories on your system +; at http://php.net/session.save-path +php_value[session.save_handler] = files +php_value[session.save_path] = /var/lib/php/session +php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache +;php_value[opcache.file_cache] = /var/lib/php/opcache \ No newline at end of file diff --git a/idrocap_wa/index.php b/idrocap_wa/index.php new file mode 100644 index 0000000..4591769 --- /dev/null +++ b/idrocap_wa/index.php @@ -0,0 +1,16 @@ + " + self.execution_command + ':\n{}'.format(completed_process.stderr.decode('utf-8'))) + if completed_process.stdout: + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ':\n{}'.format(completed_process.stdout.decode('utf-8'))) + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - RETURN CODE: {}'.format(completed_process.returncode)) + completed_process.check_returncode() + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ': Shell command successfully executed!') + self.result = True + except FileNotFoundError as error: + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - A FileNotFoundError error has occured during shell command execution:', stack_info=False, exc_info=False) + self.logger.exception(error, stack_info=False, exc_info=False) + return False + except subprocess.CalledProcessError as error: + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - A CalledProcessError has occured during processing:', stack_info=False, exc_info=False) + self.logger.exception(error, stack_info=False, exc_info=False) + self.result = False + + def __data_processing(self, channel, mr): + self.logger.info(mr) + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - Starting processing thread:') + self.result = None + thread = threading.Thread(target=self.__execute_command, args=(mr,)) + thread.start() + + while thread.is_alive(): + self.connection.process_data_events() + + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Result received:") + self.logger.info(self.result) + if (self.result is not True): + self.__send_error(json.dumps(mr)) + return self.result + + def __send_ack_nack(self, ack, channel, method): + channel.basic_ack(delivery_tag=method.delivery_tag) + if ack is True: + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Ack performed") + else: + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Ack performed BUT ERRORS OCCURRED!") + + def __data_handler(self, channel, method, properties, body): + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - New message received:') + error = False + + try: + mr = json.loads(body.decode()) + error = not self.__data_processing(channel, mr) + except json.JSONDecodeError as error: + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Malformed message", stack_info=False, exc_info=False) + self.logger.exception(error, stack_info=False, exc_info=False) + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - This message will be removed from the queue", stack_info=False, exc_info=False) + self.__send_ack_nack(False, channel, method) + time.sleep(60) + return + + if self.result is True and error is False: + self.__send_ack_nack(True, channel, method) + else: + self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - An error has occured during processing") + if self.discarding_mode is True: + self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Discarding mode enabled.") + self.__send_ack_nack(True, channel, method) + else: + self.__send_ack_nack(False, channel, method) + + time.sleep(5) + + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Data handling complete. Waiting for new messages") + + def __send_error(self, message): + self.channel.basic_publish(exchange='', routing_key=self.rabbitmq_queue+'_errors', body=message) + +if __name__ == '__main__': + formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + handler = logging.handlers.TimedRotatingFileHandler("{}{}".format(os.environ['logging_file_path'], os.environ['logging_name']), when=os.environ['logging_file_rotate_when'], interval=int(os.environ['logging_file_rotate_interval']), backupCount=int(os.environ['logging_file_backup_count'])) + handler.setFormatter(formatter) + logger = logging.getLogger(os.environ['logging_name']) + logger.addHandler(handler) + logger.setLevel(logging.DEBUG) + + app = JixelGeneralPurposeRabbitConsumer( + os.environ['RABBITMQ_USERNAME'], + os.environ['RABBITMQ_PASSWORD'], + os.environ['rabbitmq_host'], + os.environ['rabbitmq_vhost'], + os.environ['rabbitmq_port'], + os.environ['rabbitmq_queue'], + os.environ['rabbitmq_heartbeat'], + os.environ['execution_path'], + os.environ['execution_command'], + logger, + os.environ['discarding_mode'] + ) + app.consume() diff --git a/idrocap_wa/jixel-background-task-handler/jgprc.sh b/idrocap_wa/jixel-background-task-handler/jgprc.sh new file mode 100755 index 0000000..63e583b --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jgprc.sh @@ -0,0 +1,26 @@ +export rabbitmq_username='jixel' +export rabbitmq_password='jixel' +export rabbitmq_host='rabbitmq' +export rabbitmq_vhost='gp' +export rabbitmq_queue='gp' +export rabbitmq_port='5672' +export execution_path='/var/www/jixel/bin/' +export execution_command='gp' +export rabbitmq_heartbeat=60 +export discarding_mode='False' + +# Log file rotation policy: +# Current 'when' events supported: +# 'S' - Seconds +# 'M' - Minutes +# 'H' - Hours +# 'D' - Days +# 'midnight' - roll over at midnight +# 'W{0-6}' - roll over on a certain day; W0 - Monday, W1 - Tuesday, etc +export logging_file_rotate_when='H' +export logging_file_rotate_interval=24 +export logging_name='JixelGeneralPurposeRabbitConsumer' +export logging_file_path='/general_purpose_rabbit_consumer/logs/' +export logging_file_backup_count=30 + +python3 ./jgprc.py diff --git a/idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh b/idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh new file mode 100755 index 0000000..031bfff --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh @@ -0,0 +1,12 @@ +#!/bin/bash +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +/usr/bin/python3 /usr/local/ies-solutions/jixel-background-task-handler/jbth.py diff --git a/idrocap_wa/jixel-background-task-handler/jixel-cron.log b/idrocap_wa/jixel-background-task-handler/jixel-cron.log new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/jixel-background-task-handler/jixel-cron.sh b/idrocap_wa/jixel-background-task-handler/jixel-cron.sh new file mode 100755 index 0000000..d99d9d3 --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-cron.sh @@ -0,0 +1,5 @@ +#!/bin/bash +crond +crontab /usr/local/ies-solutions/jixel-cron/jixel-cron.txt +tail -f /usr/local/ies-solutions/jixel-cron/jixel-cron.txt + diff --git a/idrocap_wa/jixel-background-task-handler/jixel-cron.txt b/idrocap_wa/jixel-background-task-handler/jixel-cron.txt new file mode 100644 index 0000000..3dcf589 --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-cron.txt @@ -0,0 +1,6 @@ +# always put 3 rows: service called, date and the actual service called output: +* * * * * echo "/var/www/jixel/bin/cake" >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log +* * * * * date >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log +* * * * * /var/www/jixel/bin/cake >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log +0 0 * * 0 rm -f /usr/local/ies-solutions/jixel-cron/jixel-cron.log +# keep this line empty! \ No newline at end of file diff --git a/idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh b/idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh new file mode 100755 index 0000000..ce79ed6 --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh @@ -0,0 +1,12 @@ +#!/bin/bash +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +/usr/bin/python3 /usr/local/ies-solutions/jixel-general-purpose-rabbit-consumer/jgprc.py diff --git a/idrocap_wa/phpcs.xml b/idrocap_wa/phpcs.xml new file mode 100644 index 0000000..cb4c2dc --- /dev/null +++ b/idrocap_wa/phpcs.xml @@ -0,0 +1,12 @@ + + + + + + + */src/Controller/* + + + src/ + tests/ + diff --git a/idrocap_wa/phpstan.neon b/idrocap_wa/phpstan.neon new file mode 100644 index 0000000..c131dec --- /dev/null +++ b/idrocap_wa/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 8 + treatPhpDocTypesAsCertain: false + checkGenericClassInNonGenericObjectType: false + paths: + - src/ diff --git a/idrocap_wa/phpunit.xml.dist b/idrocap_wa/phpunit.xml.dist new file mode 100644 index 0000000..4dfd186 --- /dev/null +++ b/idrocap_wa/phpunit.xml.dist @@ -0,0 +1,37 @@ + + + + + + + + + + + tests/TestCase/ + + + + + + + + + + + + + src/ + plugins/*/src/ + + + src/Console/Installer.php + + + diff --git a/idrocap_wa/plugins/.gitkeep b/idrocap_wa/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/psalm.xml b/idrocap_wa/psalm.xml new file mode 100644 index 0000000..4e9226b --- /dev/null +++ b/idrocap_wa/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/idrocap_wa/resources/.gitkeep b/idrocap_wa/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/resources/locales/cake.pot b/idrocap_wa/resources/locales/cake.pot new file mode 100644 index 0000000..6f1c7d7 --- /dev/null +++ b/idrocap_wa/resources/locales/cake.pot @@ -0,0 +1,279 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: CakePHP 4.4.5\n" +"POT-Creation-Date: 2023-02-28 09:27+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./templates/Error/error400.php:39 +#: ./templates/Error/error500.php:43 +msgid "Error" +msgstr "" + +#: ./templates/Error/error400.php:40 +msgid "The requested address {0} was not found on this server." +msgstr "" + +#: ./templates/Error/error500.php:41 +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:361 +msgid "An Internal Error Has Occurred." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php:462 +msgid "You are not authorized to access that location." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:359 +msgid "Not Found" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:390 +msgid "Missing or incorrect CSRF cookie type." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:394 +msgid "Missing or invalid CSRF cookie." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:417 +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:265 +msgid "CSRF token from either the request body or request headers did not match or is missing." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:247 +msgid "Missing or incorrect CSRF session key" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1489 +msgid "The requested file contains `..` and will not be read." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1497 +msgid "The requested file was not found" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:116 +msgid "{0,number,#,###.##} KB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:118 +msgid "{0,number,#,###.##} MB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:120 +msgid "{0,number,#,###.##} GB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:122 +msgid "{0,number,#,###.##} TB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:114 +msgid "{0,number,integer} Byte" +msgid_plural "{0,number,integer} Bytes" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} from now" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} after" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} before" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:120 +msgid "just now" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:157 +msgid "about a second ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:158 +msgid "about a minute ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:159 +msgid "about an hour ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:160 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:370 +msgid "about a day ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:161 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:371 +msgid "about a week ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:162 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:372 +msgid "about a month ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:163 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:373 +msgid "about a year ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:174 +msgid "in about a second" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:175 +msgid "in about a minute" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:176 +msgid "in about an hour" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:177 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:384 +msgid "in about a day" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:178 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:385 +msgid "in about a week" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:179 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:386 +msgid "in about a month" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:180 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:387 +msgid "in about a year" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:342 +msgid "today" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:409 +msgid "%s ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:410 +msgid "on %s" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:53 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:132 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:354 +msgid "{0} year" +msgid_plural "{0} years" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:57 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:135 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:357 +msgid "{0} month" +msgid_plural "{0} months" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:63 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:138 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:360 +msgid "{0} week" +msgid_plural "{0} weeks" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:65 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:141 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:363 +msgid "{0} day" +msgid_plural "{0} days" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:70 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:144 +msgid "{0} hour" +msgid_plural "{0} hours" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:74 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:147 +msgid "{0} minute" +msgid_plural "{0} minutes" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:78 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:150 +msgid "{0} second" +msgid_plural "{0} seconds" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:63 +msgid "This value is already in use" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:110 +msgid "This value does not exist" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:232 +msgid "Cannot modify row: a constraint for the `{0}` association fails." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:270 +msgid "The count does not match {0}{1}" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Utility/Text.php:923 +msgid "and" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2539 +msgid "This field is required" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2559 +#: ./vendor/cakephp/cakephp/src/View/Form/ArrayContext.php:249 +msgid "This field cannot be left empty" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2711 +msgid "The provided value is invalid" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:979 +msgid "Edit {0}" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:981 +msgid "New {0}" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:1917 +msgid "Submit" +msgstr "" + diff --git a/idrocap_wa/resources/locales/default.pot b/idrocap_wa/resources/locales/default.pot new file mode 100644 index 0000000..4c05ce9 --- /dev/null +++ b/idrocap_wa/resources/locales/default.pot @@ -0,0 +1,1709 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2023-03-03 14:35+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./src/Controller/Api/AttachmentsController.php:36 +#: ./src/Controller/AttachmentsController.php:38 +#: ./src/Controller/AttachmentsController.php:68 +msgid "Allegato non trovato" +msgstr "" + +#: ./src/Controller/Api/AttachmentsController.php:37 +#: ./src/Controller/AttachmentsController.php:39 +#: ./src/Controller/AttachmentsController.php:69 +msgid "Non hai i permessi necessari per visionare l'allegato" +msgstr "" + +#: ./src/Controller/Api/OrganisationsController.php:104 +msgid "Organizzazione non trovata!" +msgstr "" + +#: ./src/Controller/Api/UsersController.php:160 +msgid "Utente non trovato!" +msgstr "" + +#: ./src/Controller/AppController.php:95 +msgid "SYSADMIN" +msgstr "" + +#: ./src/Controller/AppController.php:99 +#: ./templates/Capabilities/index.php:13 +#: ./templates/Groups/handle_capabilities.php:23 +#: ./templates/Groups/view.php:42 +msgid "Gestione competenze" +msgstr "" + +#: ./src/Controller/AppController.php:104 +msgid "Test notifiche" +msgstr "" + +#: ./src/Controller/AppController.php:107 +msgid "Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:24 +#: ./src/Controller/CapabilitiesController.php:54 +#: ./src/Controller/CapabilitiesController.php:97 +#: ./src/Controller/CapabilitiesController.php:135 +#: ./src/Controller/CapabilitiesController.php:177 +#: ./src/Controller/GroupsController.php:31 +#: ./src/Controller/GroupsController.php:54 +#: ./src/Controller/GroupsController.php:92 +#: ./src/Controller/GroupsController.php:112 +#: ./src/Controller/GroupsController.php:136 +#: ./src/Controller/GroupsController.php:160 +#: ./src/Controller/GroupsController.php:183 +#: ./src/Controller/OrganisationsController.php:32 +#: ./src/Controller/OrganisationsController.php:60 +#: ./src/Controller/OrganisationsController.php:109 +#: ./src/Controller/OrganisationsController.php:131 +#: ./src/Controller/OrganisationsController.php:155 +#: ./src/Controller/OrganisationsController.php:181 +#: ./src/Controller/UsersController.php:38 +#: ./src/Controller/UsersController.php:70 +#: ./src/Controller/UsersController.php:113 +#: ./src/Controller/UsersController.php:119 +#: ./src/Controller/UsersController.php:136 +#: ./src/Controller/UsersController.php:177 +#: ./src/Controller/UsersController.php:211 +#: ./src/Controller/UsersController.php:216 +msgid "Non hai i permessi necessari" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:79 +msgid "Competenza \"{0}\" nascosta con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:82 +msgid "Errore durante il tentativo di nascondere la Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:117 +msgid "Competenza \"{0}\" resa visibile con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:120 +msgid "Errore durante il tentativo di rendere visibile la Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:159 +msgid "Competenza \"{0}\" cancellata con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:162 +msgid "Errore durante la cancellazione della Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:197 +msgid "Competenza \"{0}\" ripristinata con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:200 +msgid "Errore durante il ripristino della Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:27 +#: ./src/Controller/DeliveriesController.php:125 +#: ./src/Controller/EmailsController.php:25 +#: ./src/Controller/EmailsController.php:64 +#: ./src/Controller/FaxesController.php:25 +#: ./src/Controller/FaxesController.php:64 +#: ./src/Controller/MobilePhonesController.php:26 +#: ./src/Controller/MobilePhonesController.php:65 +#: ./src/Controller/PhonesController.php:25 +#: ./src/Controller/PhonesController.php:64 +#: ./src/Controller/TelegramChatsController.php:25 +#: ./src/Controller/TelegramChatsController.php:63 +msgid "Gestione recapiti non prevista per questa tipologia di oggetto" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questa organizzazione" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questo utente" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:30 +msgid "Non hai i permessi per visualizzare i recapiti per {0}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:128 +msgid "Non hai i permessi per eliminare i recapiti di questo tipo per {0}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:134 +#: ./src/Model/Entity/Actor.php:87 +msgid "Cellulare ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:137 +#: ./src/Model/Entity/Actor.php:97 +msgid "Fax ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:140 +#: ./src/Model/Entity/Actor.php:107 +msgid "Email ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:143 +#: ./src/Model/Entity/Actor.php:117 +msgid "Telefono ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:146 +#: ./src/Model/Entity/Actor.php:127 +msgid "Telegram Chat ID: {0}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:154 +msgid "Il recapito \"{0}\" è stato cancellato con successo" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:156 +msgid "Errore durante la cancellazione del recapito {0}. Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/EmailsController.php:27 +#: ./src/Controller/FaxesController.php:27 +#: ./src/Controller/MobilePhonesController.php:28 +#: ./src/Controller/PhonesController.php:27 +#: ./src/Controller/TelegramChatsController.php:27 +msgid "Non hai i permessi per aggiungere i recapiti di questo tipo per {0}" +msgstr "" + +#: ./src/Controller/EmailsController.php:39 +msgid "L'Email è stata aggiunta con successo." +msgstr "" + +#: ./src/Controller/EmailsController.php:43 +msgid "Errore durante l'aggiunta dell'Email: {0}" +msgstr "" + +#: ./src/Controller/EmailsController.php:66 +#: ./src/Controller/FaxesController.php:66 +#: ./src/Controller/MobilePhonesController.php:67 +#: ./src/Controller/PhonesController.php:66 +#: ./src/Controller/TelegramChatsController.php:65 +msgid "Non hai i permessi per modificare i recapiti di questo tipo per {0}" +msgstr "" + +#: ./src/Controller/EmailsController.php:71 +msgid "L'Email è stata modificata con successo." +msgstr "" + +#: ./src/Controller/EmailsController.php:75 +msgid "Errore durante la modifica dell'Email. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/FaxesController.php:39 +msgid "Il Fax è stato aggiunto con successo." +msgstr "" + +#: ./src/Controller/FaxesController.php:43 +msgid "Errore durante l'aggiunta del Fax: {0}" +msgstr "" + +#: ./src/Controller/FaxesController.php:71 +msgid "Il Fax è stato modificato con successo." +msgstr "" + +#: ./src/Controller/FaxesController.php:75 +msgid "Errore durante la modifica del Fax. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/GroupsController.php:57 +#: ./src/Controller/OrganisationsController.php:63 +#: ./templates/Capabilities/index.php:41 +#: ./templates/Deliveries/index.php:49 +#: ./templates/Deliveries/index.php:91 +#: ./templates/Deliveries/index.php:133 +#: ./templates/Deliveries/index.php:175 +#: ./templates/Emails/add.php:48 +#: ./templates/Emails/edit.php:48 +#: ./templates/Faxes/add.php:48 +#: ./templates/Faxes/edit.php:48 +#: ./templates/Groups/add.php:38 +#: ./templates/Groups/edit.php:43 +#: ./templates/Groups/index.php:31 +#: ./templates/Groups/view.php:35 +#: ./templates/MobilePhones/add.php:48 +#: ./templates/MobilePhones/edit.php:48 +#: ./templates/Organisations/index.php:29 +#: ./templates/Phones/add.php:48 +#: ./templates/Phones/edit.php:48 +msgid "Descrizione" +msgstr "" + +#: ./src/Controller/GroupsController.php:58 +#: ./templates/Groups/add.php:39 +#: ./templates/Groups/edit.php:44 +#: ./templates/Groups/index.php:32 +#: ./templates/Groups/view.php:37 +msgid "Profilo Default" +msgstr "" + +#: ./src/Controller/GroupsController.php:59 +#: ./templates/Groups/add.php:40 +#: ./templates/Groups/edit.php:45 +#: ./templates/Groups/index.php:33 +#: ./templates/Groups/view.php:39 +msgid "Profilo Amministratore" +msgstr "" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "SI" +msgstr "" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "NO" +msgstr "" + +#: ./src/Controller/GroupsController.php:118 +msgid "Profilo Utente creato con successo." +msgstr "" + +#: ./src/Controller/GroupsController.php:122 +msgid "Errore durante la creazione del Profilo Utente: {0}" +msgstr "" + +#: ./src/Controller/GroupsController.php:142 +#: ./src/Controller/GroupsController.php:206 +msgid "Profilo Utente \"{0}\" modificato con successo." +msgstr "" + +#: ./src/Controller/GroupsController.php:146 +#: ./src/Controller/GroupsController.php:209 +msgid "Errore durante la modifica del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/GroupsController.php:166 +msgid "Il Profilo Utente \"{0}\" è stato cancellato con successo" +msgstr "" + +#: ./src/Controller/GroupsController.php:168 +msgid "Errore durante la cancellazione del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/MapsController.php:131 +msgid "Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}" +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:40 +msgid "Il Cellulare è stato aggiunto con successo." +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:44 +msgid "Errore durante l'aggiunta del Cellulare: {0}" +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:72 +msgid "Il Cellulare è stato modificato con successo." +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:76 +msgid "Errore durante la modifica del Cellulare. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/NotificationsController.php:51 +msgid "Errore durante la cancellazione della notifica: " +msgstr "" + +#: ./src/Controller/OrganisationsController.php:64 +#: ./templates/Organisations/add.php:38 +#: ./templates/Organisations/edit.php:42 +#: ./templates/Organisations/index.php:30 +#: ./templates/Organisations/view.php:37 +msgid "Acronimo" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:65 +#: ./templates/Organisations/index.php:31 +msgid "Tipologia" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:66 +#: ./templates/Maps/index.php:131 +#: ./templates/Organisations/add.php:140 +#: ./templates/Organisations/add.php:159 +#: ./templates/Organisations/edit.php:63 +#: ./templates/Organisations/index.php:32 +#: ./templates/Organisations/view.php:52 +#: ./templates/Users/add.php:46 +#: ./templates/Users/edit.php:51 +#: ./templates/Users/view.php:55 +msgid "Indirizzo" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:67 +#: ./templates/Maps/index.php:120 +#: ./templates/Organisations/add.php:129 +#: ./templates/Organisations/add.php:161 +#: ./templates/Organisations/edit.php:65 +#: ./templates/Organisations/index.php:34 +#: ./templates/Organisations/view.php:54 +msgid "Comune" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:68 +#: ./templates/Organisations/add.php:160 +#: ./templates/Organisations/edit.php:64 +#: ./templates/Organisations/index.php:33 +#: ./templates/Organisations/view.php:53 +#: ./templates/Users/add.php:48 +#: ./templates/Users/edit.php:53 +#: ./templates/Users/view.php:59 +msgid "CAP" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:69 +#: ./templates/Maps/index.php:109 +#: ./templates/Organisations/add.php:118 +#: ./templates/Organisations/add.php:162 +#: ./templates/Organisations/edit.php:66 +#: ./templates/Organisations/index.php:35 +#: ./templates/Organisations/view.php:55 +msgid "Provincia" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:70 +#: ./src/Controller/UsersController.php:76 +#: ./templates/Organisations/index.php:36 +#: ./templates/Organisations/view.php:56 +#: ./templates/Users/index.php:32 +msgid "Recapiti" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:137 +msgid "Organizzazione creata con successo." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:141 +msgid "Errore durante la creazione dell'organizzazione: {0}" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:163 +msgid "Organizzazione \"{0}\" modificata con successo." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:167 +msgid "Errore durante la modifica dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:188 +msgid "Impossibile eliminare l'organizzazione \"{0}\". Ci sono {1} utenti collegati ad essa." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:193 +msgid "L'organizzazione \"{0}\" è stata cancellata con successo" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:195 +msgid "Errore durante la cancellazione dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/PhonesController.php:39 +msgid "Il Telefono è stato aggiunto con successo." +msgstr "" + +#: ./src/Controller/PhonesController.php:43 +msgid "Errore durante l'aggiunta del Telefono: {0}" +msgstr "" + +#: ./src/Controller/PhonesController.php:71 +msgid "Il Telefono è stato modificato con successo." +msgstr "" + +#: ./src/Controller/PhonesController.php:75 +msgid "Errore durante la modifica del Telefono. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:39 +msgid "La Chat Telegram è stata aggiunta con successo." +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:43 +msgid "Errore durante l'aggiunta della Chat Telegram: {0}" +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:70 +msgid "La Chat Telegram è stata modificata con successo." +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:74 +msgid "Errore durante la modifica della Chat Telegram. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/UsersController.php:73 +#: ./templates/Users/add.php:41 +#: ./templates/Users/edit.php:46 +#: ./templates/Users/index.php:29 +#: ./templates/Users/view.php:45 +msgid "Cognome" +msgstr "" + +#: ./src/Controller/UsersController.php:74 +#: ./templates/ControllableObjects/get_attachments.php:59 +#: ./templates/Organisations/add.php:37 +#: ./templates/Organisations/edit.php:41 +#: ./templates/Organisations/view.php:36 +#: ./templates/Users/add.php:40 +#: ./templates/Users/edit.php:45 +#: ./templates/Users/index.php:30 +#: ./templates/Users/view.php:43 +msgid "Nome" +msgstr "" + +#: ./src/Controller/UsersController.php:75 +#: ./templates/Users/index.php:31 +msgid "Username" +msgstr "" + +#: ./src/Controller/UsersController.php:77 +#: ./templates/Users/add.php:52 +#: ./templates/Users/edit.php:57 +#: ./templates/Users/index.php:33 +#: ./templates/Users/view.php:65 +msgid "Profili" +msgstr "" + +#: ./src/Controller/UsersController.php:78 +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +#: ./templates/Users/add.php:50 +#: ./templates/Users/edit.php:55 +#: ./templates/Users/index.php:34 +#: ./templates/Users/view.php:63 +msgid "Organizzazione" +msgstr "" + +#: ./src/Controller/UsersController.php:156 +msgid "Utente creato con successo." +msgstr "" + +#: ./src/Controller/UsersController.php:160 +msgid "Errore durante la creazione dell'utente: {0}" +msgstr "" + +#: ./src/Controller/UsersController.php:190 +msgid "Utente \"{0}\" modificato con successo." +msgstr "" + +#: ./src/Controller/UsersController.php:194 +msgid "Errore durante la modifica dell'utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/UsersController.php:219 +msgid "L'utente \"{0}\" è stato cancellato con successo" +msgstr "" + +#: ./src/Controller/UsersController.php:221 +msgid "Errore durante la cancellazione dell'utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/UsersController.php:244 +msgid "Ho dimenticato la mia password" +msgstr "" + +#: ./src/Controller/UsersController.php:256 +msgid "Logout eseguito con successo." +msgstr "" + +#: ./src/Controller/UsersController.php:294 +msgid "Inserire un indirizzo email valido!" +msgstr "" + +#: ./src/Controller/UsersController.php:306 +msgid "A breve riceverai un'email all'indirizzo \"{0}\" con le istruzioni per eseguire il reset della password per il tuo account con username \"{1}\"." +msgstr "" + +#: ./src/Controller/UsersController.php:311 +msgid "L'indirizzo email inserito non risulta presente" +msgstr "" + +#: ./src/Controller/UsersController.php:316 +#: ./src/Controller/UsersController.php:364 +msgid "Ritorna al login" +msgstr "" + +#: ./src/Controller/UsersController.php:332 +msgid "Impossibile completare la procedura di recupero password." +msgstr "" + +#: ./src/Controller/UsersController.php:355 +msgid "Impossibile cambiare la password" +msgstr "" + +#: ./src/Controller/UsersController.php:359 +msgid "La nuova password non è valida e/o le 2 password non coincidono" +msgstr "" + +#: ./src/Controller/UsersController.php:397 +msgid "Errore durante l'eliminazione della foto utente!" +msgstr "" + +#: ./src/Controller/UsersController.php:399 +msgid "Foto utente eliminata con successo" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:41 +msgid "Test Test Test" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:43 +msgid "Hai ricevuto questo messaggio di test perchè sei registrato/a sulla piattaforma {0} ed hai almeno un recapito abilitato alla ricezione delle notifiche" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:46 +msgid "Recupero password {0}" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:50 +msgid "Hai ricevuto questo messaggio perchè sei registrato/a sulla piattaforma {0} ed è stata richiesta la procedura di recupero credenziali per il tuo account. Se non hai richiesto tale procedura ti preghiamo di ignorare questo messaggio. Per accedere a {0} utilizza il seguente username: \" {1} \" . Clicca sul seguente link per impostare una nuova password " +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:53 +msgid "{0} mancante" +msgstr "" + +#: ./src/Model/Behavior/AttachmentsBehavior.php:132 +msgid "L'allegato è obbligatorio!" +msgstr "" + +#: ./src/Model/Entity/ControllableObject.php:241 +msgid "Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "" + +#: ./src/Model/Table/EmailsTable.php:107 +msgid "Indirizzo email già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/FaxesTable.php:103 +msgid "Fax già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/MobilePhonesTable.php:107 +msgid "Cellulare già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/OrganisationsTable.php:169 +msgid "Le geometrie inserite per georeferenziare l'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "" + +#: ./src/Model/Table/PhonesTable.php:99 +msgid "Telefono già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/PushNotificationsTable.php:97 +msgid "Non puoi associare nuovamente questo token allo stesso utente" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:106 +msgid "La password deve contenere almeno {0} caratteri" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:111 +msgid "La password deve contenere almeno {0} carattere/i maiuscolo/i" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:117 +msgid "La password deve contenere almeno {0} numero/i" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:131 +msgid "La password deve contenere almeno {1} carattere/i speciale/i tra \"{0}\"" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:256 +msgid "Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)" +msgstr "" + +#: ./src/View/Cell/MapCell.php:182 +msgid "Geometrie disegnate" +msgstr "" + +#: ./templates/Capabilities/index.php:9 +#: ./templates/Deliveries/index.php:9 +#: ./templates/Emails/add.php:9 +#: ./templates/Emails/edit.php:9 +#: ./templates/Faxes/add.php:9 +#: ./templates/Faxes/edit.php:9 +#: ./templates/Groups/add.php:9 +#: ./templates/Groups/edit.php:9 +#: ./templates/Groups/handle_capabilities.php:9 +#: ./templates/Groups/index.php:9 +#: ./templates/Groups/view.php:9 +#: ./templates/Maps/index.php:9 +#: ./templates/MobilePhones/add.php:9 +#: ./templates/MobilePhones/edit.php:9 +#: ./templates/Organisations/add.php:9 +#: ./templates/Organisations/edit.php:9 +#: ./templates/Organisations/index.php:9 +#: ./templates/Organisations/view.php:9 +#: ./templates/Phones/add.php:9 +#: ./templates/Phones/edit.php:9 +#: ./templates/TelegramChats/add.php:9 +#: ./templates/TelegramChats/edit.php:9 +#: ./templates/Users/add.php:9 +#: ./templates/Users/edit.php:9 +#: ./templates/Users/index.php:9 +#: ./templates/Users/view.php:9 +msgid "Configurazioni" +msgstr "" + +#: ./templates/Capabilities/index.php:24 +msgid "Lista delle competenze" +msgstr "" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca per descrizione competenza o codice o nome del gruppo di competenze" +msgstr "" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca" +msgstr "" + +#: ./templates/Capabilities/index.php:42 +msgid "Codice" +msgstr "" + +#: ./templates/Capabilities/index.php:43 +msgid "Priorità" +msgstr "" + +#: ./templates/Capabilities/index.php:44 +msgid "Gruppo" +msgstr "" + +#: ./templates/Capabilities/index.php:45 +#: ./templates/ControllableObjects/get_attachments.php:66 +#: ./templates/Deliveries/index.php:52 +#: ./templates/Deliveries/index.php:94 +#: ./templates/Deliveries/index.php:136 +#: ./templates/Deliveries/index.php:177 +#: ./templates/Deliveries/index.php:217 +#: ./templates/Groups/index.php:34 +#: ./templates/Organisations/index.php:37 +#: ./templates/Users/index.php:35 +msgid "Azioni" +msgstr "" + +#: ./templates/Capabilities/index.php:57 +#: ./templates/Groups/handle_capabilities.php:57 +#: ./templates/Groups/handle_capabilities.php:58 +#: ./templates/Groups/handle_capabilities.php:59 +msgid "Competenza non visibile e non configurabile dai non SYSADMIN" +msgstr "" + +#: ./templates/Capabilities/index.php:58 +msgid "Competenza eliminata dal sistema" +msgstr "" + +#: ./templates/Capabilities/index.php:67 +msgid "Nascondi" +msgstr "" + +#: ./templates/Capabilities/index.php:67 +msgid "Mostra" +msgstr "" + +#: ./templates/Capabilities/index.php:68 +msgid "Ripristina" +msgstr "" + +#: ./templates/Capabilities/index.php:68 +#: ./templates/Deliveries/index.php:63 +#: ./templates/Deliveries/index.php:105 +#: ./templates/Deliveries/index.php:147 +#: ./templates/Deliveries/index.php:187 +#: ./templates/Deliveries/index.php:227 +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Cancella" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Allegati presenti: {0}" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Nessun Allegato presente" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:60 +msgid "Georeferenziazione" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:62 +msgid "Dimensione" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:63 +msgid "Tipo" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:64 +msgid "Caricato il" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:65 +#: ./templates/cell/Filters/display.php:57 +msgid "Da" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:80 +msgid "File pubblico" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:83 +msgid "File privato" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:106 +msgid "Visualizza" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:110 +msgid "Segna da eliminare" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come non rilevante" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come rilevante" +msgstr "" + +#: ./templates/Dashboard/index.php:16 +msgid "Jixel Dashboard" +msgstr "" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Lista {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Organizzazioni" +msgstr "" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Utenti" +msgstr "" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Dettaglio {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Utente" +msgstr "" + +#: ./templates/Deliveries/index.php:23 +#: ./templates/Emails/add.php:23 +#: ./templates/Emails/edit.php:23 +#: ./templates/Faxes/add.php:23 +#: ./templates/Faxes/edit.php:23 +#: ./templates/MobilePhones/add.php:23 +#: ./templates/MobilePhones/edit.php:23 +#: ./templates/Organisations/view.php:69 +#: ./templates/Phones/add.php:23 +#: ./templates/Phones/edit.php:23 +#: ./templates/TelegramChats/add.php:23 +#: ./templates/TelegramChats/edit.php:23 +#: ./templates/Users/view.php:70 +msgid "Gestione recapiti" +msgstr "" + +#: ./templates/Deliveries/index.php:31 +msgid "Recapiti associati a {0} \"{1}\"" +msgstr "" + +#: ./templates/Deliveries/index.php:41 +msgid "Cellulare: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:50 +#: ./templates/MobilePhones/add.php:47 +#: ./templates/MobilePhones/edit.php:47 +msgid "Cellulare" +msgstr "" + +#: ./templates/Deliveries/index.php:51 +#: ./templates/Deliveries/index.php:93 +#: ./templates/Deliveries/index.php:135 +#: ./templates/Deliveries/index.php:216 +#: ./templates/Emails/add.php:49 +#: ./templates/Emails/edit.php:49 +#: ./templates/Faxes/add.php:49 +#: ./templates/Faxes/edit.php:49 +#: ./templates/MobilePhones/add.php:49 +#: ./templates/MobilePhones/edit.php:49 +#: ./templates/TelegramChats/add.php:48 +#: ./templates/TelegramChats/edit.php:48 +msgid "Ricevi notifiche a questo recapito" +msgstr "" + +#: ./templates/Deliveries/index.php:62 +#: ./templates/Deliveries/index.php:104 +#: ./templates/Deliveries/index.php:146 +#: ./templates/Deliveries/index.php:186 +#: ./templates/Deliveries/index.php:226 +#: ./templates/Groups/index.php:45 +#: ./templates/Groups/view.php:43 +#: ./templates/Organisations/index.php:53 +#: ./templates/Organisations/view.php:70 +#: ./templates/Users/index.php:49 +#: ./templates/Users/view.php:71 +msgid "Modifica" +msgstr "" + +#: ./templates/Deliveries/index.php:63 +msgid "Sei sicuro che vuoi cancellare il Cellulare \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:73 +#: ./templates/MobilePhones/add.php:28 +msgid "Aggiungi Cellulare" +msgstr "" + +#: ./templates/Deliveries/index.php:84 +msgid "Fax: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:92 +#: ./templates/Faxes/add.php:47 +#: ./templates/Faxes/edit.php:47 +msgid "Fax" +msgstr "" + +#: ./templates/Deliveries/index.php:105 +msgid "Sei sicuro che vuoi cancellare il Fax \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:115 +#: ./templates/Faxes/add.php:28 +msgid "Aggiungi Fax" +msgstr "" + +#: ./templates/Deliveries/index.php:126 +msgid "Email: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:134 +#: ./templates/Emails/add.php:47 +#: ./templates/Emails/edit.php:47 +msgid "Email" +msgstr "" + +#: ./templates/Deliveries/index.php:147 +msgid "Sei sicuro che vuoi cancellare l'Email \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:157 +#: ./templates/Emails/add.php:28 +msgid "Aggiungi Email" +msgstr "" + +#: ./templates/Deliveries/index.php:168 +msgid "Telefono: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:176 +#: ./templates/Phones/add.php:47 +#: ./templates/Phones/edit.php:47 +msgid "Telefono" +msgstr "" + +#: ./templates/Deliveries/index.php:187 +msgid "Sei sicuro che vuoi cancellare il Telefono \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:197 +#: ./templates/Phones/add.php:28 +msgid "Aggiungi Telefono" +msgstr "" + +#: ./templates/Deliveries/index.php:208 +msgid "Chat Telegram: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:215 +msgid "ID" +msgstr "" + +#: ./templates/Deliveries/index.php:227 +msgid "Sei sicuro che vuoi cancellare la Chat Telegram con ID \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:237 +#: ./templates/TelegramChats/add.php:28 +msgid "Aggiungi Chat Telegram" +msgstr "" + +#: ./templates/Emails/add.php:40 +msgid "Aggiungi Email per {0} \"{1}\"" +msgstr "" + +#: ./templates/Emails/add.php:54 +#: ./templates/Emails/edit.php:54 +#: ./templates/Faxes/add.php:54 +#: ./templates/Faxes/edit.php:54 +#: ./templates/Groups/add.php:45 +#: ./templates/Groups/edit.php:50 +#: ./templates/Groups/handle_capabilities.php:71 +#: ./templates/MobilePhones/add.php:54 +#: ./templates/MobilePhones/edit.php:54 +#: ./templates/Organisations/add.php:172 +#: ./templates/Organisations/edit.php:86 +#: ./templates/Phones/add.php:53 +#: ./templates/Phones/edit.php:53 +#: ./templates/TelegramChats/add.php:53 +#: ./templates/TelegramChats/edit.php:53 +#: ./templates/Users/add.php:57 +#: ./templates/Users/choose_new_password.php:8 +#: ./templates/Users/edit.php:62 +msgid "Salva" +msgstr "" + +#: ./templates/Emails/edit.php:28 +msgid "Modifica Email" +msgstr "" + +#: ./templates/Emails/edit.php:40 +msgid "Modifica Email per {0} \"{1}\"" +msgstr "" + +#: ./templates/Faxes/add.php:40 +msgid "Aggiungi Fax per {0} \"{1}\"" +msgstr "" + +#: ./templates/Faxes/edit.php:28 +msgid "Modifica Fax" +msgstr "" + +#: ./templates/Faxes/edit.php:40 +msgid "Modifica Fax per {0} \"{1}\"" +msgstr "" + +#: ./templates/Groups/add.php:13 +#: ./templates/Groups/edit.php:13 +#: ./templates/Groups/handle_capabilities.php:13 +#: ./templates/Groups/index.php:13 +#: ./templates/Groups/index.php:24 +#: ./templates/Groups/view.php:13 +msgid "Lista dei Profili Utente" +msgstr "" + +#: ./templates/Groups/add.php:18 +#: ./templates/Groups/add.php:31 +msgid "Nuovo Profilo Utente" +msgstr "" + +#: ./templates/Groups/edit.php:18 +#: ./templates/Groups/handle_capabilities.php:18 +#: ./templates/Groups/view.php:18 +msgid "Dettaglio Profilo Utente" +msgstr "" + +#: ./templates/Groups/edit.php:23 +#: ./templates/Groups/edit.php:36 +msgid "Modifica Profilo Utente" +msgstr "" + +#: ./templates/Groups/handle_capabilities.php:35 +msgid "Competenze associate al Profilo Utente \"{0}\"" +msgstr "" + +#: ./templates/Groups/handle_capabilities.php:45 +msgid "Gruppo di competenze non visibile e non configurabile dai non SYSADMIN" +msgstr "" + +#: ./templates/Groups/handle_capabilities.php:52 +msgid "Gruppo di competenze \"{0}\"" +msgstr "" + +#: ./templates/Groups/index.php:44 +#: ./templates/Organisations/index.php:52 +#: ./templates/Users/index.php:48 +#: ./templates/plugin/AdminLTE/element/nav-top.php:118 +msgid "Dettaglio" +msgstr "" + +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +msgid "Sei sicuro che vuoi cancellare il profilo \"{0}\" ?" +msgstr "" + +#: ./templates/Groups/view.php:30 +msgid "Informazioni Profilo Utente" +msgstr "" + +#: ./templates/Maps/index.php:25 +msgid "Mappa" +msgstr "" + +#: ./templates/Maps/index.php:30 +msgid "Campo esistente appartenente al form ospite" +msgstr "" + +#: ./templates/Maps/index.php:37 +msgid "Posizione Evento" +msgstr "" + +#: ./templates/Maps/index.php:54 +msgid "Collezione di geometrie" +msgstr "" + +#: ./templates/Maps/index.php:65 +#: ./templates/Organisations/add.php:74 +msgid "Longitudine" +msgstr "" + +#: ./templates/Maps/index.php:76 +#: ./templates/Organisations/add.php:85 +msgid "Latitudine" +msgstr "" + +#: ./templates/Maps/index.php:87 +#: ./templates/Organisations/add.php:96 +#: ./templates/Organisations/add.php:158 +#: ./templates/Organisations/edit.php:62 +#: ./templates/Organisations/view.php:51 +msgid "Coordinate (Longitudine Latitudine)" +msgstr "" + +#: ./templates/Maps/index.php:98 +#: ./templates/Organisations/add.php:107 +msgid "Cap" +msgstr "" + +#: ./templates/Maps/index.php:142 +#: ./templates/Organisations/add.php:151 +msgid "Descrizione luogo" +msgstr "" + +#: ./templates/MobilePhones/add.php:40 +msgid "Aggiungi Cellulare per {0} \"{1}\"" +msgstr "" + +#: ./templates/MobilePhones/edit.php:28 +msgid "Modifica Cellulare" +msgstr "" + +#: ./templates/MobilePhones/edit.php:40 +msgid "Modifica Cellulare per {0} \"{1}\"" +msgstr "" + +#: ./templates/Organisations/add.php:13 +#: ./templates/Organisations/edit.php:13 +#: ./templates/Organisations/index.php:13 +#: ./templates/Organisations/view.php:13 +msgid "Lista Organizzazioni" +msgstr "" + +#: ./templates/Organisations/add.php:18 +#: ./templates/Organisations/add.php:30 +msgid "Nuova Organizzazione" +msgstr "" + +#: ./templates/Organisations/add.php:39 +#: ./templates/Organisations/edit.php:43 +#: ./templates/Organisations/view.php:38 +msgid "Tipo organizzazione" +msgstr "" + +#: ./templates/Organisations/add.php:46 +#: ./templates/Organisations/edit.php:50 +#: ./templates/Organisations/view.php:45 +msgid "Posizione Organizzazione" +msgstr "" + +#: ./templates/Organisations/edit.php:18 +#: ./templates/Organisations/view.php:18 +#: ./templates/Organisations/view.php:29 +msgid "Dettaglio Organizzazione" +msgstr "" + +#: ./templates/Organisations/edit.php:23 +#: ./templates/Organisations/edit.php:34 +msgid "Modifica Organizzazione" +msgstr "" + +#: ./templates/Organisations/index.php:23 +msgid "Lista delle {0} Organizzazioni" +msgstr "" + +#: ./templates/Organisations/index.php:23 +#: ./templates/Users/index.php:23 +msgid "{0} su {1}" +msgstr "" + +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +msgid "Sei sicuro che vuoi cancellare l'organizzazione \"{0}\" ?" +msgstr "" + +#: ./templates/Phones/add.php:40 +msgid "Aggiungi Telefono per {0} \"{1}\"" +msgstr "" + +#: ./templates/Phones/edit.php:28 +msgid "Modifica Telefono" +msgstr "" + +#: ./templates/Phones/edit.php:40 +msgid "Modifica Telefono per {0} \"{1}\"" +msgstr "" + +#: ./templates/TelegramChats/add.php:40 +msgid "Aggiungi Chat Telegram per {0} \"{1}\"" +msgstr "" + +#: ./templates/TelegramChats/add.php:47 +#: ./templates/TelegramChats/edit.php:47 +msgid "Chat Telegram ID" +msgstr "" + +#: ./templates/TelegramChats/edit.php:28 +msgid "Modifica Chat Telegram" +msgstr "" + +#: ./templates/TelegramChats/edit.php:40 +msgid "Modifica Chat Telegram per {0} \"{1}\"" +msgstr "" + +#: ./templates/Users/add.php:13 +#: ./templates/Users/edit.php:13 +#: ./templates/Users/index.php:13 +#: ./templates/Users/view.php:13 +msgid "Lista Utenti" +msgstr "" + +#: ./templates/Users/add.php:18 +#: ./templates/Users/add.php:31 +msgid "Nuovo Utente" +msgstr "" + +#: ./templates/Users/add.php:38 +#: ./templates/Users/edit.php:43 +#: ./templates/Users/view.php:41 +msgid "Nome utente" +msgstr "" + +#: ./templates/Users/add.php:39 +#: ./templates/Users/edit.php:44 +msgid "Password" +msgstr "" + +#: ./templates/Users/add.php:42 +#: ./templates/Users/edit.php:47 +#: ./templates/Users/view.php:47 +msgid "Codice Fiscale" +msgstr "" + +#: ./templates/Users/add.php:43 +#: ./templates/Users/edit.php:48 +#: ./templates/Users/view.php:49 +msgid "Data di nascita" +msgstr "" + +#: ./templates/Users/add.php:44 +#: ./templates/Users/edit.php:49 +#: ./templates/Users/view.php:51 +msgid "Luogo di nascita" +msgstr "" + +#: ./templates/Users/add.php:45 +#: ./templates/Users/edit.php:50 +#: ./templates/Users/view.php:53 +msgid "Sesso" +msgstr "" + +#: ./templates/Users/add.php:47 +#: ./templates/Users/edit.php:52 +#: ./templates/Users/view.php:57 +msgid "Città" +msgstr "" + +#: ./templates/Users/add.php:49 +#: ./templates/Users/edit.php:54 +#: ./templates/Users/view.php:61 +msgid "Lingua preferita" +msgstr "" + +#: ./templates/Users/add.php:51 +#: ./templates/Users/edit.php:56 +msgid "Foto del profilo (solo jpeg di dimensioni 160x160!)" +msgstr "" + +#: ./templates/Users/choose_new_password.php:4 +msgid "Imposta una nuova password" +msgstr "" + +#: ./templates/Users/choose_new_password.php:5 +msgid "Digita la nuova password" +msgstr "" + +#: ./templates/Users/choose_new_password.php:6 +msgid "Ridigita la nuova password" +msgstr "" + +#: ./templates/Users/edit.php:18 +#: ./templates/Users/view.php:18 +msgid "Dettaglio Utente" +msgstr "" + +#: ./templates/Users/edit.php:23 +#: ./templates/Users/edit.php:36 +msgid "Modifica Utente" +msgstr "" + +#: ./templates/Users/index.php:23 +msgid "Lista dei {0} Utenti" +msgstr "" + +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Sei sicuro che vuoi cancellare l'utente \"{0}\" ?" +msgstr "" + +#: ./templates/Users/login.php:4 +msgid "Accedi" +msgstr "" + +#: ./templates/Users/login.php:8 +msgid "Login" +msgstr "" + +#: ./templates/Users/password_recovery.php:4 +msgid "Inserisci un indirizzo email associato alla tua utenza" +msgstr "" + +#: ./templates/Users/password_recovery.php:7 +msgid "Richiedi reset password" +msgstr "" + +#: ./templates/Users/view.php:30 +msgid "Informazioni Utente" +msgstr "" + +#: ./templates/Users/view.php:34 +msgid "Elimina foto" +msgstr "" + +#: ./templates/Users/view.php:34 +msgid "Sei sicuro che vuoi eliminare la foto ?" +msgstr "" + +#: ./templates/Users/view.php:62 +msgid "Non specificata" +msgstr "" + +#: ./templates/Users/view.php:67 +msgid "Recapiti:" +msgstr "" + +#: ./templates/cell/FilterInput/display.php:9 +#: ./templates/element/attachments.php:127 +msgid "Rimuovi" +msgstr "" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:113 +msgid "Filtri attivi" +msgstr "" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:116 +msgid "Filtri disattivati" +msgstr "" + +#: ./templates/cell/Filters/display.php:15 +msgid "Aggiungi un filtro" +msgstr "" + +#: ./templates/cell/Filters/display.php:34 +#: ./templates/cell/Filters/display.php:55 +msgid "Applica" +msgstr "" + +#: ./templates/cell/Filters/display.php:39 +msgid "Reset" +msgstr "" + +#: ./templates/cell/Filters/display.php:56 +msgid "Annulla" +msgstr "" + +#: ./templates/cell/Filters/display.php:58 +msgid "A" +msgstr "" + +#: ./templates/cell/Filters/display.php:59 +msgid "Dal Al" +msgstr "" + +#: ./templates/cell/Filters/display.php:60 +#: ./templates/cell/Filters/display.php:87 +msgid "Oggi" +msgstr "" + +#: ./templates/cell/Filters/display.php:62 +msgid "Dom" +msgstr "" + +#: ./templates/cell/Filters/display.php:63 +msgid "Lun" +msgstr "" + +#: ./templates/cell/Filters/display.php:64 +msgid "Mar" +msgstr "" + +#: ./templates/cell/Filters/display.php:65 +msgid "Mer" +msgstr "" + +#: ./templates/cell/Filters/display.php:66 +msgid "Gio" +msgstr "" + +#: ./templates/cell/Filters/display.php:67 +msgid "Ven" +msgstr "" + +#: ./templates/cell/Filters/display.php:68 +msgid "Sab" +msgstr "" + +#: ./templates/cell/Filters/display.php:71 +msgid "Gennaio" +msgstr "" + +#: ./templates/cell/Filters/display.php:72 +msgid "Febbraio" +msgstr "" + +#: ./templates/cell/Filters/display.php:73 +msgid "Marzo" +msgstr "" + +#: ./templates/cell/Filters/display.php:74 +msgid "Aprile" +msgstr "" + +#: ./templates/cell/Filters/display.php:75 +msgid "Maggio" +msgstr "" + +#: ./templates/cell/Filters/display.php:76 +msgid "Giugno" +msgstr "" + +#: ./templates/cell/Filters/display.php:77 +msgid "Luglio" +msgstr "" + +#: ./templates/cell/Filters/display.php:78 +msgid "Agosto" +msgstr "" + +#: ./templates/cell/Filters/display.php:79 +msgid "Settembre" +msgstr "" + +#: ./templates/cell/Filters/display.php:80 +msgid "Ottobre" +msgstr "" + +#: ./templates/cell/Filters/display.php:81 +msgid "Novembre" +msgstr "" + +#: ./templates/cell/Filters/display.php:82 +msgid "Dicembre" +msgstr "" + +#: ./templates/cell/Filters/display.php:88 +msgid "Ieri" +msgstr "" + +#: ./templates/cell/Filters/display.php:89 +msgid "Questa settimana" +msgstr "" + +#: ./templates/cell/Filters/display.php:90 +msgid "Questo mese" +msgstr "" + +#: ./templates/cell/Filters/display.php:91 +msgid "Lo scorso mese" +msgstr "" + +#: ./templates/cell/Filters/display.php:92 +msgid "Ultimi 7 giorni" +msgstr "" + +#: ./templates/cell/Filters/display.php:93 +msgid "Ultimi 15 giorni" +msgstr "" + +#: ./templates/cell/Filters/display.php:94 +msgid "Ultimi 30 giorni" +msgstr "" + +#: ./templates/cell/Filters/display.php:131 +msgid "Errore durante il recupero del filtro selezionato. Riprovare di nuovo" +msgstr "" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:118 +#: ./templates/element/Map.php:122 +msgid "OpenStreetMap ONLINE" +msgstr "" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:127 +#: ./templates/element/Map.php:131 +msgid "OpenStreetMap OFFLINE" +msgstr "" + +#: ./templates/element/Map.php:312 +#: ./templates/element/Map.php:541 +msgid "Indirizzo non trovato o fuori dall'area di competenza" +msgstr "" + +#: ./templates/element/Map.php:530 +msgid "Punto alle coordinate (EPSG:4326) Latitudine:" +msgstr "" + +#: ./templates/element/Map.php:530 +msgid "Longitudine:" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:10 +msgid "Scegli un risultato:" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:30 +msgid "Inserisci un indirizzo o le coordinate (in formato EPSG:4326)" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:31 +msgid "Cerca un indirizzo" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:36 +msgid "Inserisci un punto in mappa" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:41 +msgid "Inserisci un poligono in mappa" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:46 +msgid "Inserisci un cerchio in mappa" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:51 +msgid "Cancella una geometria" +msgstr "" + +#: ./templates/element/attachmentPreview.php:16 +msgid "Il tuo browser non supporta HTML5 video tag. Prova ad aggiornare il tuo browser." +msgstr "" + +#: ./templates/element/attachmentPreview.php:35 +msgid "Anteprima non disponibile" +msgstr "" + +#: ./templates/element/attachments.php:30 +msgid "di tipo: \"{0}\"" +msgstr "" + +#: ./templates/element/attachments.php:39 +msgid "Mostra allegati correlati" +msgstr "" + +#: ./templates/element/attachments.php:48 +msgid "Allega un file " +msgstr "" + +#: ./templates/element/attachments.php:48 +msgid "Allega files " +msgstr "" + +#: ./templates/element/attachments.php:54 +msgid "Allega file pubblico " +msgstr "" + +#: ./templates/element/attachments.php:54 +msgid "Allega un file privato " +msgstr "" + +#: ./templates/element/attachments.php:54 +msgid "Allega files privati " +msgstr "" + +#: ./templates/element/attachments.php:58 +msgid "Allega files..." +msgstr "" + +#: ./templates/element/attachments.php:65 +msgid "Allega files {1} {0}" +msgstr "" + +#: ./templates/element/attachments.php:118 +msgid "latitudine" +msgstr "" + +#: ./templates/element/attachments.php:119 +msgid "longitudine" +msgstr "" + +#: ./templates/layout/error.php:38 +msgid "Back" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/aside-control-sidebar.php:4 +msgid "Notifiche" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/footer.php:6 +msgid "Versione" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/footer.php:9 +msgid "Tutti i diritti riservati" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:67 +msgid "Nuove notifiche: {0}" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:91 +msgid "Segna tutte le notifiche come lette" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:121 +msgid "Esci" +msgstr "" + diff --git a/idrocap_wa/resources/locales/en/default.po b/idrocap_wa/resources/locales/en/default.po new file mode 100644 index 0000000..bd63efb --- /dev/null +++ b/idrocap_wa/resources/locales/en/default.po @@ -0,0 +1,1709 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2023-03-03 14:35+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./src/Controller/Api/AttachmentsController.php:36 +#: ./src/Controller/AttachmentsController.php:38 +#: ./src/Controller/AttachmentsController.php:68 +msgid "Allegato non trovato" +msgstr "Attachment not found" + +#: ./src/Controller/Api/AttachmentsController.php:37 +#: ./src/Controller/AttachmentsController.php:39 +#: ./src/Controller/AttachmentsController.php:69 +msgid "Non hai i permessi necessari per visionare l'allegato" +msgstr "You do not have permission to view the attachment" + +#: ./src/Controller/Api/OrganisationsController.php:104 +msgid "Organizzazione non trovata!" +msgstr "Organisation not found!" + +#: ./src/Controller/Api/UsersController.php:160 +msgid "Utente non trovato!" +msgstr "User not found!" + +#: ./src/Controller/AppController.php:95 +msgid "SYSADMIN" +msgstr "SYSADMIN" + +#: ./src/Controller/AppController.php:99 +#: ./templates/Capabilities/index.php:13 +#: ./templates/Groups/handle_capabilities.php:23 +#: ./templates/Groups/view.php:42 +msgid "Gestione competenze" +msgstr "Handle capabilities" + +#: ./src/Controller/AppController.php:104 +msgid "Test notifiche" +msgstr "Test notification system" + +#: ./src/Controller/AppController.php:107 +msgid "Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?" +msgstr "Notifications will be sent to all users and organisations that have at least one notification enabled contact! Are you sure you want to proceed ?" + +#: ./src/Controller/CapabilitiesController.php:24 +#: ./src/Controller/CapabilitiesController.php:54 +#: ./src/Controller/CapabilitiesController.php:97 +#: ./src/Controller/CapabilitiesController.php:135 +#: ./src/Controller/CapabilitiesController.php:177 +#: ./src/Controller/GroupsController.php:31 +#: ./src/Controller/GroupsController.php:54 +#: ./src/Controller/GroupsController.php:92 +#: ./src/Controller/GroupsController.php:112 +#: ./src/Controller/GroupsController.php:136 +#: ./src/Controller/GroupsController.php:160 +#: ./src/Controller/GroupsController.php:183 +#: ./src/Controller/OrganisationsController.php:32 +#: ./src/Controller/OrganisationsController.php:60 +#: ./src/Controller/OrganisationsController.php:109 +#: ./src/Controller/OrganisationsController.php:131 +#: ./src/Controller/OrganisationsController.php:155 +#: ./src/Controller/OrganisationsController.php:181 +#: ./src/Controller/UsersController.php:38 +#: ./src/Controller/UsersController.php:70 +#: ./src/Controller/UsersController.php:113 +#: ./src/Controller/UsersController.php:119 +#: ./src/Controller/UsersController.php:136 +#: ./src/Controller/UsersController.php:177 +#: ./src/Controller/UsersController.php:211 +#: ./src/Controller/UsersController.php:216 +msgid "Non hai i permessi necessari" +msgstr "You do not have needed permissions" + +#: ./src/Controller/CapabilitiesController.php:79 +msgid "Competenza \"{0}\" nascosta con successo!" +msgstr "Capability \"{0}\" successfully hidden!" + +#: ./src/Controller/CapabilitiesController.php:82 +msgid "Errore durante il tentativo di nascondere la Competenza \"{0}\"!" +msgstr "Error trying to hide the capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:117 +msgid "Competenza \"{0}\" resa visibile con successo!" +msgstr "Capability \"{0}\" successfully set unhidden!" + +#: ./src/Controller/CapabilitiesController.php:120 +msgid "Errore durante il tentativo di rendere visibile la Competenza \"{0}\"!" +msgstr "Error trying to set the capability \"{0}\" unhidden!" + +#: ./src/Controller/CapabilitiesController.php:159 +msgid "Competenza \"{0}\" cancellata con successo!" +msgstr "Capability \"{0}\" successfully deleted!" + +#: ./src/Controller/CapabilitiesController.php:162 +msgid "Errore durante la cancellazione della Competenza \"{0}\"!" +msgstr "Error trying to delete the Capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:197 +msgid "Competenza \"{0}\" ripristinata con successo!" +msgstr "Capability \"{0}\" successfully restored!" + +#: ./src/Controller/CapabilitiesController.php:200 +msgid "Errore durante il ripristino della Competenza \"{0}\"!" +msgstr "Error trying to restore the capability \"{0}\"!" + +#: ./src/Controller/DeliveriesController.php:27 +#: ./src/Controller/DeliveriesController.php:125 +#: ./src/Controller/EmailsController.php:25 +#: ./src/Controller/EmailsController.php:64 +#: ./src/Controller/FaxesController.php:25 +#: ./src/Controller/FaxesController.php:64 +#: ./src/Controller/MobilePhonesController.php:26 +#: ./src/Controller/MobilePhonesController.php:65 +#: ./src/Controller/PhonesController.php:25 +#: ./src/Controller/PhonesController.php:64 +#: ./src/Controller/TelegramChatsController.php:25 +#: ./src/Controller/TelegramChatsController.php:63 +msgid "Gestione recapiti non prevista per questa tipologia di oggetto" +msgstr "Contacts management is not expected for this type of object" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questa organizzazione" +msgstr "this organisation" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questo utente" +msgstr "this user" + +#: ./src/Controller/DeliveriesController.php:30 +msgid "Non hai i permessi per visualizzare i recapiti per {0}" +msgstr "You do not have permission to view contacts for {0}" + +#: ./src/Controller/DeliveriesController.php:128 +msgid "Non hai i permessi per eliminare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to delete contacts of this type for {0}" + +#: ./src/Controller/DeliveriesController.php:134 +#: ./src/Model/Entity/Actor.php:87 +msgid "Cellulare ({0}): {1}" +msgstr "Mobile Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:137 +#: ./src/Model/Entity/Actor.php:97 +msgid "Fax ({0}): {1}" +msgstr "Fax ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:140 +#: ./src/Model/Entity/Actor.php:107 +msgid "Email ({0}): {1}" +msgstr "Email ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:143 +#: ./src/Model/Entity/Actor.php:117 +msgid "Telefono ({0}): {1}" +msgstr "Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:146 +#: ./src/Model/Entity/Actor.php:127 +msgid "Telegram Chat ID: {0}" +msgstr "Telegram Chat ID: {0}" + +#: ./src/Controller/DeliveriesController.php:154 +msgid "Il recapito \"{0}\" è stato cancellato con successo" +msgstr "Contact \"{0}\" successfully deleted" + +#: ./src/Controller/DeliveriesController.php:156 +msgid "Errore durante la cancellazione del recapito {0}. Riprovare di nuovo." +msgstr "Error trying to delete contact {0}. Please try again." + +#: ./src/Controller/EmailsController.php:27 +#: ./src/Controller/FaxesController.php:27 +#: ./src/Controller/MobilePhonesController.php:28 +#: ./src/Controller/PhonesController.php:27 +#: ./src/Controller/TelegramChatsController.php:27 +msgid "Non hai i permessi per aggiungere i recapiti di questo tipo per {0}" +msgstr "You do not have permission to add this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:39 +msgid "L'Email è stata aggiunta con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:43 +msgid "Errore durante l'aggiunta dell'Email: {0}" +msgstr "Error trying adding Email: {0}" + +#: ./src/Controller/EmailsController.php:66 +#: ./src/Controller/FaxesController.php:66 +#: ./src/Controller/MobilePhonesController.php:67 +#: ./src/Controller/PhonesController.php:66 +#: ./src/Controller/TelegramChatsController.php:65 +msgid "Non hai i permessi per modificare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to edit this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:71 +msgid "L'Email è stata modificata con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:75 +msgid "Errore durante la modifica dell'Email. Riprovare di nuovo" +msgstr "Error trying to edit Email contact. Please try again" + +#: ./src/Controller/FaxesController.php:39 +msgid "Il Fax è stato aggiunto con successo." +msgstr "Fax successfully added." + +#: ./src/Controller/FaxesController.php:43 +msgid "Errore durante l'aggiunta del Fax: {0}" +msgstr "Error trying to add Fax: {0}" + +#: ./src/Controller/FaxesController.php:71 +msgid "Il Fax è stato modificato con successo." +msgstr "Fax successfully updated." + +#: ./src/Controller/FaxesController.php:75 +msgid "Errore durante la modifica del Fax. Riprovare di nuovo" +msgstr "Error trying to edit Fax. Please try again" + +#: ./src/Controller/GroupsController.php:57 +#: ./src/Controller/OrganisationsController.php:63 +#: ./templates/Capabilities/index.php:41 +#: ./templates/Deliveries/index.php:49 +#: ./templates/Deliveries/index.php:91 +#: ./templates/Deliveries/index.php:133 +#: ./templates/Deliveries/index.php:175 +#: ./templates/Emails/add.php:48 +#: ./templates/Emails/edit.php:48 +#: ./templates/Faxes/add.php:48 +#: ./templates/Faxes/edit.php:48 +#: ./templates/Groups/add.php:38 +#: ./templates/Groups/edit.php:43 +#: ./templates/Groups/index.php:31 +#: ./templates/Groups/view.php:35 +#: ./templates/MobilePhones/add.php:48 +#: ./templates/MobilePhones/edit.php:48 +#: ./templates/Organisations/index.php:29 +#: ./templates/Phones/add.php:48 +#: ./templates/Phones/edit.php:48 +msgid "Descrizione" +msgstr "Description" + +#: ./src/Controller/GroupsController.php:58 +#: ./templates/Groups/add.php:39 +#: ./templates/Groups/edit.php:44 +#: ./templates/Groups/index.php:32 +#: ./templates/Groups/view.php:37 +msgid "Profilo Default" +msgstr "Default Profile" + +#: ./src/Controller/GroupsController.php:59 +#: ./templates/Groups/add.php:40 +#: ./templates/Groups/edit.php:45 +#: ./templates/Groups/index.php:33 +#: ./templates/Groups/view.php:39 +msgid "Profilo Amministratore" +msgstr "Admin Profile" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "SI" +msgstr "YES" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "NO" +msgstr "NO" + +#: ./src/Controller/GroupsController.php:118 +msgid "Profilo Utente creato con successo." +msgstr "User Profile successfully created." + +#: ./src/Controller/GroupsController.php:122 +msgid "Errore durante la creazione del Profilo Utente: {0}" +msgstr "Error trying to create User Profile: {0}" + +#: ./src/Controller/GroupsController.php:142 +#: ./src/Controller/GroupsController.php:206 +msgid "Profilo Utente \"{0}\" modificato con successo." +msgstr "User Profile \"{0}\" successfully updated." + +#: ./src/Controller/GroupsController.php:146 +#: ./src/Controller/GroupsController.php:209 +msgid "Errore durante la modifica del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/GroupsController.php:166 +msgid "Il Profilo Utente \"{0}\" è stato cancellato con successo" +msgstr "\"{0}\" User Profile successfully deleted" + +#: ./src/Controller/GroupsController.php:168 +msgid "Errore durante la cancellazione del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/MapsController.php:131 +msgid "Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}" +msgstr "Point at coordinates (EPSG:4326) Latitude: {0}, Longitude: {1}" + +#: ./src/Controller/MobilePhonesController.php:40 +msgid "Il Cellulare è stato aggiunto con successo." +msgstr "Mobile Phone contact successfully created." + +#: ./src/Controller/MobilePhonesController.php:44 +msgid "Errore durante l'aggiunta del Cellulare: {0}" +msgstr "Error trying to create Mobile Phone: {0}" + +#: ./src/Controller/MobilePhonesController.php:72 +msgid "Il Cellulare è stato modificato con successo." +msgstr "Mobile Phone successfully updated." + +#: ./src/Controller/MobilePhonesController.php:76 +msgid "Errore durante la modifica del Cellulare. Riprovare di nuovo" +msgstr "Error trying to edit Mobile Phone. Please try again" + +#: ./src/Controller/NotificationsController.php:51 +msgid "Errore durante la cancellazione della notifica: " +msgstr "Error trying to delete the notification: " + +#: ./src/Controller/OrganisationsController.php:64 +#: ./templates/Organisations/add.php:38 +#: ./templates/Organisations/edit.php:42 +#: ./templates/Organisations/index.php:30 +#: ./templates/Organisations/view.php:37 +msgid "Acronimo" +msgstr "Acronym" + +#: ./src/Controller/OrganisationsController.php:65 +#: ./templates/Organisations/index.php:31 +msgid "Tipologia" +msgstr "Typology" + +#: ./src/Controller/OrganisationsController.php:66 +#: ./templates/Maps/index.php:131 +#: ./templates/Organisations/add.php:140 +#: ./templates/Organisations/add.php:159 +#: ./templates/Organisations/edit.php:63 +#: ./templates/Organisations/index.php:32 +#: ./templates/Organisations/view.php:52 +#: ./templates/Users/add.php:46 +#: ./templates/Users/edit.php:51 +#: ./templates/Users/view.php:55 +msgid "Indirizzo" +msgstr "Address" + +#: ./src/Controller/OrganisationsController.php:67 +#: ./templates/Maps/index.php:120 +#: ./templates/Organisations/add.php:129 +#: ./templates/Organisations/add.php:161 +#: ./templates/Organisations/edit.php:65 +#: ./templates/Organisations/index.php:34 +#: ./templates/Organisations/view.php:54 +msgid "Comune" +msgstr "District" + +#: ./src/Controller/OrganisationsController.php:68 +#: ./templates/Organisations/add.php:160 +#: ./templates/Organisations/edit.php:64 +#: ./templates/Organisations/index.php:33 +#: ./templates/Organisations/view.php:53 +#: ./templates/Users/add.php:48 +#: ./templates/Users/edit.php:53 +#: ./templates/Users/view.php:59 +msgid "CAP" +msgstr "ZIP code" + +#: ./src/Controller/OrganisationsController.php:69 +#: ./templates/Maps/index.php:109 +#: ./templates/Organisations/add.php:118 +#: ./templates/Organisations/add.php:162 +#: ./templates/Organisations/edit.php:66 +#: ./templates/Organisations/index.php:35 +#: ./templates/Organisations/view.php:55 +msgid "Provincia" +msgstr "Province" + +#: ./src/Controller/OrganisationsController.php:70 +#: ./src/Controller/UsersController.php:76 +#: ./templates/Organisations/index.php:36 +#: ./templates/Organisations/view.php:56 +#: ./templates/Users/index.php:32 +msgid "Recapiti" +msgstr "Contacts" + +#: ./src/Controller/OrganisationsController.php:137 +msgid "Organizzazione creata con successo." +msgstr "Organisation successfully created." + +#: ./src/Controller/OrganisationsController.php:141 +msgid "Errore durante la creazione dell'organizzazione: {0}" +msgstr "Error trying to create the organisation: {0}" + +#: ./src/Controller/OrganisationsController.php:163 +msgid "Organizzazione \"{0}\" modificata con successo." +msgstr "Organisation \"{0}\" successfully updated." + +#: ./src/Controller/OrganisationsController.php:167 +msgid "Errore durante la modifica dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the organisation \"{0}\". Please try again." + +#: ./src/Controller/OrganisationsController.php:188 +msgid "Impossibile eliminare l'organizzazione \"{0}\". Ci sono {1} utenti collegati ad essa." +msgstr "Unable to delete the organisation \"{0}\". There are {1} belonging users." + +#: ./src/Controller/OrganisationsController.php:193 +msgid "L'organizzazione \"{0}\" è stata cancellata con successo" +msgstr "Organisation \"{0}\" successfully deleted" + +#: ./src/Controller/OrganisationsController.php:195 +msgid "Errore durante la cancellazione dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the organisation \"{0}\". Please try again." + +#: ./src/Controller/PhonesController.php:39 +msgid "Il Telefono è stato aggiunto con successo." +msgstr "Phone successfully created." + +#: ./src/Controller/PhonesController.php:43 +msgid "Errore durante l'aggiunta del Telefono: {0}" +msgstr "Error trying to create Phone: {0}" + +#: ./src/Controller/PhonesController.php:71 +msgid "Il Telefono è stato modificato con successo." +msgstr "Phone successfully updated." + +#: ./src/Controller/PhonesController.php:75 +msgid "Errore durante la modifica del Telefono. Riprovare di nuovo" +msgstr "Error trying to edit Phone. Please try again" + +#: ./src/Controller/TelegramChatsController.php:39 +msgid "La Chat Telegram è stata aggiunta con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:43 +msgid "Errore durante l'aggiunta della Chat Telegram: {0}" +msgstr "Error trying to create Telegram Chat: {0}" + +#: ./src/Controller/TelegramChatsController.php:70 +msgid "La Chat Telegram è stata modificata con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:74 +msgid "Errore durante la modifica della Chat Telegram. Riprovare di nuovo" +msgstr "Error trying to edit Telegram Chat. Please try again" + +#: ./src/Controller/UsersController.php:73 +#: ./templates/Users/add.php:41 +#: ./templates/Users/edit.php:46 +#: ./templates/Users/index.php:29 +#: ./templates/Users/view.php:45 +msgid "Cognome" +msgstr "Surname" + +#: ./src/Controller/UsersController.php:74 +#: ./templates/ControllableObjects/get_attachments.php:59 +#: ./templates/Organisations/add.php:37 +#: ./templates/Organisations/edit.php:41 +#: ./templates/Organisations/view.php:36 +#: ./templates/Users/add.php:40 +#: ./templates/Users/edit.php:45 +#: ./templates/Users/index.php:30 +#: ./templates/Users/view.php:43 +msgid "Nome" +msgstr "Name" + +#: ./src/Controller/UsersController.php:75 +#: ./templates/Users/index.php:31 +msgid "Username" +msgstr "Username" + +#: ./src/Controller/UsersController.php:77 +#: ./templates/Users/add.php:52 +#: ./templates/Users/edit.php:57 +#: ./templates/Users/index.php:33 +#: ./templates/Users/view.php:65 +msgid "Profili" +msgstr "Profiles" + +#: ./src/Controller/UsersController.php:78 +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +#: ./templates/Users/add.php:50 +#: ./templates/Users/edit.php:55 +#: ./templates/Users/index.php:34 +#: ./templates/Users/view.php:63 +msgid "Organizzazione" +msgstr "Organisation" + +#: ./src/Controller/UsersController.php:156 +msgid "Utente creato con successo." +msgstr "User successfully created." + +#: ./src/Controller/UsersController.php:160 +msgid "Errore durante la creazione dell'utente: {0}" +msgstr "Error trying to create user: {0}" + +#: ./src/Controller/UsersController.php:190 +msgid "Utente \"{0}\" modificato con successo." +msgstr "User \"{0}\" successfully updated." + +#: ./src/Controller/UsersController.php:194 +msgid "Errore durante la modifica dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:219 +msgid "L'utente \"{0}\" è stato cancellato con successo" +msgstr "User \"{0}\" successfully deleted" + +#: ./src/Controller/UsersController.php:221 +msgid "Errore durante la cancellazione dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:244 +msgid "Ho dimenticato la mia password" +msgstr "I forgot my password" + +#: ./src/Controller/UsersController.php:256 +msgid "Logout eseguito con successo." +msgstr "Successfully logged out." + +#: ./src/Controller/UsersController.php:294 +msgid "Inserire un indirizzo email valido!" +msgstr "Insert a valid email address!" + +#: ./src/Controller/UsersController.php:306 +msgid "A breve riceverai un'email all'indirizzo \"{0}\" con le istruzioni per eseguire il reset della password per il tuo account con username \"{1}\"." +msgstr "You will receive shortly an email at \"{0}\" with the instructions to reset the password for your account with username \"{1}\"." + +#: ./src/Controller/UsersController.php:311 +msgid "L'indirizzo email inserito non risulta presente" +msgstr "The email address you inserted is not valid or does not exists" + +#: ./src/Controller/UsersController.php:316 +#: ./src/Controller/UsersController.php:364 +msgid "Ritorna al login" +msgstr "Back to login" + +#: ./src/Controller/UsersController.php:332 +msgid "Impossibile completare la procedura di recupero password." +msgstr "Unable to complete reset password procedure. Please try again." + +#: ./src/Controller/UsersController.php:355 +msgid "Impossibile cambiare la password" +msgstr "Unable to change the password" + +#: ./src/Controller/UsersController.php:359 +msgid "La nuova password non è valida e/o le 2 password non coincidono" +msgstr "Either the new password is invalid or the two passwords don't match" + +#: ./src/Controller/UsersController.php:397 +msgid "Errore durante l'eliminazione della foto utente!" +msgstr "Error trying to delete the user photo!" + +#: ./src/Controller/UsersController.php:399 +msgid "Foto utente eliminata con successo" +msgstr "User photo successfully deleted" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:41 +msgid "Test Test Test" +msgstr "Test Test Test" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:43 +msgid "Hai ricevuto questo messaggio di test perchè sei registrato/a sulla piattaforma {0} ed hai almeno un recapito abilitato alla ricezione delle notifiche" +msgstr "You're receiving this message because you are a registered user to {0} platform and you have at least one notification enabled contact" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:46 +msgid "Recupero password {0}" +msgstr "{0} password reset" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:50 +msgid "Hai ricevuto questo messaggio perchè sei registrato/a sulla piattaforma {0} ed è stata richiesta la procedura di recupero credenziali per il tuo account. Se non hai richiesto tale procedura ti preghiamo di ignorare questo messaggio. Per accedere a {0} utilizza il seguente username: \" {1} \" . Clicca sul seguente link per impostare una nuova password " +msgstr "You're receiving this message because you are a registered user to {0} platform and you requested a password reset for your account. Plese disregard this message if you didn't request it or if you changed your mind. Please use the following username to gain access to your account: \" {1} \" . Follow this link to reset your password instead " + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:53 +msgid "{0} mancante" +msgstr "Missing \"{0}\" notification code" + +#: ./src/Model/Behavior/AttachmentsBehavior.php:132 +msgid "L'allegato è obbligatorio!" +msgstr "The attachment is mandatory!" + +#: ./src/Model/Entity/ControllableObject.php:241 +msgid "Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The given coordinates used to georeferencing one or more attachments are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/EmailsTable.php:107 +msgid "Indirizzo email già presente a sistema!" +msgstr "Email address already exists!" + +#: ./src/Model/Table/FaxesTable.php:103 +msgid "Fax già presente a sistema!" +msgstr "Fax already exists!" + +#: ./src/Model/Table/MobilePhonesTable.php:107 +msgid "Cellulare già presente a sistema!" +msgstr "Mobile Phone already exists!" + +#: ./src/Model/Table/OrganisationsTable.php:169 +msgid "Le geometrie inserite per georeferenziare l'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The inserted geometries used to georeferenciate the organisation, are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/PhonesTable.php:99 +msgid "Telefono già presente a sistema!" +msgstr "Phone already exists!" + +#: ./src/Model/Table/PushNotificationsTable.php:97 +msgid "Non puoi associare nuovamente questo token allo stesso utente" +msgstr "You cannot use this push notification token again with this user" + +#: ./src/Model/Table/UsersTable.php:106 +msgid "La password deve contenere almeno {0} caratteri" +msgstr "The password must contain at least {0} characters" + +#: ./src/Model/Table/UsersTable.php:111 +msgid "La password deve contenere almeno {0} carattere/i maiuscolo/i" +msgstr "The password must contain at least {0} uppercase characters" + +#: ./src/Model/Table/UsersTable.php:117 +msgid "La password deve contenere almeno {0} numero/i" +msgstr "The password must contain at least {0} numbers" + +#: ./src/Model/Table/UsersTable.php:131 +msgid "La password deve contenere almeno {1} carattere/i speciale/i tra \"{0}\"" +msgstr "The password must contain at least {1} special characters to be chosen among \"{0}\"" + +#: ./src/Model/Table/UsersTable.php:256 +msgid "Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)" +msgstr "Error trying to save user photo. Please make sure that the photo you are trying to save is in the correct format and size (jpeg 160x160)" + +#: ./src/View/Cell/MapCell.php:182 +msgid "Geometrie disegnate" +msgstr "Drawn geometries" + +#: ./templates/Capabilities/index.php:9 +#: ./templates/Deliveries/index.php:9 +#: ./templates/Emails/add.php:9 +#: ./templates/Emails/edit.php:9 +#: ./templates/Faxes/add.php:9 +#: ./templates/Faxes/edit.php:9 +#: ./templates/Groups/add.php:9 +#: ./templates/Groups/edit.php:9 +#: ./templates/Groups/handle_capabilities.php:9 +#: ./templates/Groups/index.php:9 +#: ./templates/Groups/view.php:9 +#: ./templates/Maps/index.php:9 +#: ./templates/MobilePhones/add.php:9 +#: ./templates/MobilePhones/edit.php:9 +#: ./templates/Organisations/add.php:9 +#: ./templates/Organisations/edit.php:9 +#: ./templates/Organisations/index.php:9 +#: ./templates/Organisations/view.php:9 +#: ./templates/Phones/add.php:9 +#: ./templates/Phones/edit.php:9 +#: ./templates/TelegramChats/add.php:9 +#: ./templates/TelegramChats/edit.php:9 +#: ./templates/Users/add.php:9 +#: ./templates/Users/edit.php:9 +#: ./templates/Users/index.php:9 +#: ./templates/Users/view.php:9 +msgid "Configurazioni" +msgstr "Configurations" + +#: ./templates/Capabilities/index.php:24 +msgid "Lista delle competenze" +msgstr "Capabilities list" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca per descrizione competenza o codice o nome del gruppo di competenze" +msgstr "Search by capability description, code or capability group name" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca" +msgstr "Search" + +#: ./templates/Capabilities/index.php:42 +msgid "Codice" +msgstr "Code" + +#: ./templates/Capabilities/index.php:43 +msgid "Priorità" +msgstr "Priority" + +#: ./templates/Capabilities/index.php:44 +msgid "Gruppo" +msgstr "Group" + +#: ./templates/Capabilities/index.php:45 +#: ./templates/ControllableObjects/get_attachments.php:66 +#: ./templates/Deliveries/index.php:52 +#: ./templates/Deliveries/index.php:94 +#: ./templates/Deliveries/index.php:136 +#: ./templates/Deliveries/index.php:177 +#: ./templates/Deliveries/index.php:217 +#: ./templates/Groups/index.php:34 +#: ./templates/Organisations/index.php:37 +#: ./templates/Users/index.php:35 +msgid "Azioni" +msgstr "Actions" + +#: ./templates/Capabilities/index.php:57 +#: ./templates/Groups/handle_capabilities.php:57 +#: ./templates/Groups/handle_capabilities.php:58 +#: ./templates/Groups/handle_capabilities.php:59 +msgid "Competenza non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability not visible and not configurable by non SYSADMIN users" + +#: ./templates/Capabilities/index.php:58 +msgid "Competenza eliminata dal sistema" +msgstr "Capability successfully deleted" + +#: ./templates/Capabilities/index.php:67 +msgid "Nascondi" +msgstr "Hide" + +#: ./templates/Capabilities/index.php:67 +msgid "Mostra" +msgstr "Show" + +#: ./templates/Capabilities/index.php:68 +msgid "Ripristina" +msgstr "Restore" + +#: ./templates/Capabilities/index.php:68 +#: ./templates/Deliveries/index.php:63 +#: ./templates/Deliveries/index.php:105 +#: ./templates/Deliveries/index.php:147 +#: ./templates/Deliveries/index.php:187 +#: ./templates/Deliveries/index.php:227 +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Cancella" +msgstr "Delete" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Allegati presenti: {0}" +msgstr "Attachments: {0}" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Nessun Allegato presente" +msgstr "No Attachments" + +#: ./templates/ControllableObjects/get_attachments.php:60 +msgid "Georeferenziazione" +msgstr "Georeferencing" + +#: ./templates/ControllableObjects/get_attachments.php:62 +msgid "Dimensione" +msgstr "Size" + +#: ./templates/ControllableObjects/get_attachments.php:63 +msgid "Tipo" +msgstr "Type" + +#: ./templates/ControllableObjects/get_attachments.php:64 +msgid "Caricato il" +msgstr "Uploaded" + +#: ./templates/ControllableObjects/get_attachments.php:65 +#: ./templates/cell/Filters/display.php:57 +msgid "Da" +msgstr "From" + +#: ./templates/ControllableObjects/get_attachments.php:80 +msgid "File pubblico" +msgstr "Public file" + +#: ./templates/ControllableObjects/get_attachments.php:83 +msgid "File privato" +msgstr "Private file" + +#: ./templates/ControllableObjects/get_attachments.php:106 +msgid "Visualizza" +msgstr "View" + +#: ./templates/ControllableObjects/get_attachments.php:110 +msgid "Segna da eliminare" +msgstr "Mark as to be deleted" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come non rilevante" +msgstr "Mark as not relevant" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come rilevante" +msgstr "Mark as relevant" + +#: ./templates/Dashboard/index.php:16 +msgid "Jixel Dashboard" +msgstr "Jixel Dashboard" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Lista {0}" +msgstr "List {0}" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Organizzazioni" +msgstr "Organisations" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Utenti" +msgstr "Users" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Dettaglio {0}" +msgstr "{0} Details" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Utente" +msgstr "User" + +#: ./templates/Deliveries/index.php:23 +#: ./templates/Emails/add.php:23 +#: ./templates/Emails/edit.php:23 +#: ./templates/Faxes/add.php:23 +#: ./templates/Faxes/edit.php:23 +#: ./templates/MobilePhones/add.php:23 +#: ./templates/MobilePhones/edit.php:23 +#: ./templates/Organisations/view.php:69 +#: ./templates/Phones/add.php:23 +#: ./templates/Phones/edit.php:23 +#: ./templates/TelegramChats/add.php:23 +#: ./templates/TelegramChats/edit.php:23 +#: ./templates/Users/view.php:70 +msgid "Gestione recapiti" +msgstr "Contacts management" + +#: ./templates/Deliveries/index.php:31 +msgid "Recapiti associati a {0} \"{1}\"" +msgstr "Associated contacts to {0} \"{1}\"" + +#: ./templates/Deliveries/index.php:41 +msgid "Cellulare: {0}" +msgstr "Mobile Phone {0}" + +#: ./templates/Deliveries/index.php:50 +#: ./templates/MobilePhones/add.php:47 +#: ./templates/MobilePhones/edit.php:47 +msgid "Cellulare" +msgstr "Mobile Phone" + +#: ./templates/Deliveries/index.php:51 +#: ./templates/Deliveries/index.php:93 +#: ./templates/Deliveries/index.php:135 +#: ./templates/Deliveries/index.php:216 +#: ./templates/Emails/add.php:49 +#: ./templates/Emails/edit.php:49 +#: ./templates/Faxes/add.php:49 +#: ./templates/Faxes/edit.php:49 +#: ./templates/MobilePhones/add.php:49 +#: ./templates/MobilePhones/edit.php:49 +#: ./templates/TelegramChats/add.php:48 +#: ./templates/TelegramChats/edit.php:48 +msgid "Ricevi notifiche a questo recapito" +msgstr "Receive notifications at this contact" + +#: ./templates/Deliveries/index.php:62 +#: ./templates/Deliveries/index.php:104 +#: ./templates/Deliveries/index.php:146 +#: ./templates/Deliveries/index.php:186 +#: ./templates/Deliveries/index.php:226 +#: ./templates/Groups/index.php:45 +#: ./templates/Groups/view.php:43 +#: ./templates/Organisations/index.php:53 +#: ./templates/Organisations/view.php:70 +#: ./templates/Users/index.php:49 +#: ./templates/Users/view.php:71 +msgid "Modifica" +msgstr "Edit" + +#: ./templates/Deliveries/index.php:63 +msgid "Sei sicuro che vuoi cancellare il Cellulare \"{0}\" ?" +msgstr "Are you sure you want to delete the Mobile Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:73 +#: ./templates/MobilePhones/add.php:28 +msgid "Aggiungi Cellulare" +msgstr "Add Mobile Phone" + +#: ./templates/Deliveries/index.php:84 +msgid "Fax: {0}" +msgstr "Fax: {0}" + +#: ./templates/Deliveries/index.php:92 +#: ./templates/Faxes/add.php:47 +#: ./templates/Faxes/edit.php:47 +msgid "Fax" +msgstr "Fax" + +#: ./templates/Deliveries/index.php:105 +msgid "Sei sicuro che vuoi cancellare il Fax \"{0}\" ?" +msgstr "Are you sure you want to delete the Fax \"{0}\" ?" + +#: ./templates/Deliveries/index.php:115 +#: ./templates/Faxes/add.php:28 +msgid "Aggiungi Fax" +msgstr "Add Fax" + +#: ./templates/Deliveries/index.php:126 +msgid "Email: {0}" +msgstr "Email: {0}" + +#: ./templates/Deliveries/index.php:134 +#: ./templates/Emails/add.php:47 +#: ./templates/Emails/edit.php:47 +msgid "Email" +msgstr "Email" + +#: ./templates/Deliveries/index.php:147 +msgid "Sei sicuro che vuoi cancellare l'Email \"{0}\" ?" +msgstr "Are you sure you want to delete the Email \"{0}\" ?" + +#: ./templates/Deliveries/index.php:157 +#: ./templates/Emails/add.php:28 +msgid "Aggiungi Email" +msgstr "Add Email" + +#: ./templates/Deliveries/index.php:168 +msgid "Telefono: {0}" +msgstr "Phone {0}" + +#: ./templates/Deliveries/index.php:176 +#: ./templates/Phones/add.php:47 +#: ./templates/Phones/edit.php:47 +msgid "Telefono" +msgstr "Phone" + +#: ./templates/Deliveries/index.php:187 +msgid "Sei sicuro che vuoi cancellare il Telefono \"{0}\" ?" +msgstr "Are you sure you want to delete the Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:197 +#: ./templates/Phones/add.php:28 +msgid "Aggiungi Telefono" +msgstr "Add Phone" + +#: ./templates/Deliveries/index.php:208 +msgid "Chat Telegram: {0}" +msgstr "Telegram Chat: {0}" + +#: ./templates/Deliveries/index.php:215 +msgid "ID" +msgstr "ID" + +#: ./templates/Deliveries/index.php:227 +msgid "Sei sicuro che vuoi cancellare la Chat Telegram con ID \"{0}\" ?" +msgstr "Are you sure you want to delete the Telegram Chat with ID \"{0}\" ?" + +#: ./templates/Deliveries/index.php:237 +#: ./templates/TelegramChats/add.php:28 +msgid "Aggiungi Chat Telegram" +msgstr "Add Telegram Chat" + +#: ./templates/Emails/add.php:40 +msgid "Aggiungi Email per {0} \"{1}\"" +msgstr "Add Email for {0} \"{1}\"" + +#: ./templates/Emails/add.php:54 +#: ./templates/Emails/edit.php:54 +#: ./templates/Faxes/add.php:54 +#: ./templates/Faxes/edit.php:54 +#: ./templates/Groups/add.php:45 +#: ./templates/Groups/edit.php:50 +#: ./templates/Groups/handle_capabilities.php:71 +#: ./templates/MobilePhones/add.php:54 +#: ./templates/MobilePhones/edit.php:54 +#: ./templates/Organisations/add.php:172 +#: ./templates/Organisations/edit.php:86 +#: ./templates/Phones/add.php:53 +#: ./templates/Phones/edit.php:53 +#: ./templates/TelegramChats/add.php:53 +#: ./templates/TelegramChats/edit.php:53 +#: ./templates/Users/add.php:57 +#: ./templates/Users/choose_new_password.php:8 +#: ./templates/Users/edit.php:62 +msgid "Salva" +msgstr "Save" + +#: ./templates/Emails/edit.php:28 +msgid "Modifica Email" +msgstr "Edit Email" + +#: ./templates/Emails/edit.php:40 +msgid "Modifica Email per {0} \"{1}\"" +msgstr "Edit Email for {0} \"{1}\"" + +#: ./templates/Faxes/add.php:40 +msgid "Aggiungi Fax per {0} \"{1}\"" +msgstr "Add Fax for {0} \"{1}\"" + +#: ./templates/Faxes/edit.php:28 +msgid "Modifica Fax" +msgstr "Edit Fax" + +#: ./templates/Faxes/edit.php:40 +msgid "Modifica Fax per {0} \"{1}\"" +msgstr "Edit Fax for {0} \"{1}\"" + +#: ./templates/Groups/add.php:13 +#: ./templates/Groups/edit.php:13 +#: ./templates/Groups/handle_capabilities.php:13 +#: ./templates/Groups/index.php:13 +#: ./templates/Groups/index.php:24 +#: ./templates/Groups/view.php:13 +msgid "Lista dei Profili Utente" +msgstr "User Profiles List" + +#: ./templates/Groups/add.php:18 +#: ./templates/Groups/add.php:31 +msgid "Nuovo Profilo Utente" +msgstr "New User Profile" + +#: ./templates/Groups/edit.php:18 +#: ./templates/Groups/handle_capabilities.php:18 +#: ./templates/Groups/view.php:18 +msgid "Dettaglio Profilo Utente" +msgstr "User Profile Details" + +#: ./templates/Groups/edit.php:23 +#: ./templates/Groups/edit.php:36 +msgid "Modifica Profilo Utente" +msgstr "Edit User Profile" + +#: ./templates/Groups/handle_capabilities.php:35 +msgid "Competenze associate al Profilo Utente \"{0}\"" +msgstr "User Profile \"{0}\" associated capabilities" + +#: ./templates/Groups/handle_capabilities.php:45 +msgid "Gruppo di competenze non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability Groups not visible and not configurable by non SYSADMIN users" + +#: ./templates/Groups/handle_capabilities.php:52 +msgid "Gruppo di competenze \"{0}\"" +msgstr "Capability Group \"{0}\"" + +#: ./templates/Groups/index.php:44 +#: ./templates/Organisations/index.php:52 +#: ./templates/Users/index.php:48 +#: ./templates/plugin/AdminLTE/element/nav-top.php:118 +msgid "Dettaglio" +msgstr "Details" + +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +msgid "Sei sicuro che vuoi cancellare il profilo \"{0}\" ?" +msgstr "Are you sure you want to delete the user profile \"{0}\" ?" + +#: ./templates/Groups/view.php:30 +msgid "Informazioni Profilo Utente" +msgstr "User Profile Informations" + +#: ./templates/Maps/index.php:25 +msgid "Mappa" +msgstr "Map" + +#: ./templates/Maps/index.php:30 +msgid "Campo esistente appartenente al form ospite" +msgstr "Existing field that belongs to the hosting form" + +#: ./templates/Maps/index.php:37 +msgid "Posizione Evento" +msgstr "Incident location" + +#: ./templates/Maps/index.php:54 +msgid "Collezione di geometrie" +msgstr "Geometry collection" + +#: ./templates/Maps/index.php:65 +#: ./templates/Organisations/add.php:74 +msgid "Longitudine" +msgstr "Longitude" + +#: ./templates/Maps/index.php:76 +#: ./templates/Organisations/add.php:85 +msgid "Latitudine" +msgstr "Latitude" + +#: ./templates/Maps/index.php:87 +#: ./templates/Organisations/add.php:96 +#: ./templates/Organisations/add.php:158 +#: ./templates/Organisations/edit.php:62 +#: ./templates/Organisations/view.php:51 +msgid "Coordinate (Longitudine Latitudine)" +msgstr "Coordinates (Longitude Latitude)" + +#: ./templates/Maps/index.php:98 +#: ./templates/Organisations/add.php:107 +msgid "Cap" +msgstr "ZIP code" + +#: ./templates/Maps/index.php:142 +#: ./templates/Organisations/add.php:151 +msgid "Descrizione luogo" +msgstr "Location description" + +#: ./templates/MobilePhones/add.php:40 +msgid "Aggiungi Cellulare per {0} \"{1}\"" +msgstr "Add Mobile Phone for {0} \"{1}\"" + +#: ./templates/MobilePhones/edit.php:28 +msgid "Modifica Cellulare" +msgstr "Edit Mobile Phone" + +#: ./templates/MobilePhones/edit.php:40 +msgid "Modifica Cellulare per {0} \"{1}\"" +msgstr "Edit Mobile Phone for {0} \"{1}\"" + +#: ./templates/Organisations/add.php:13 +#: ./templates/Organisations/edit.php:13 +#: ./templates/Organisations/index.php:13 +#: ./templates/Organisations/view.php:13 +msgid "Lista Organizzazioni" +msgstr "Organisations List" + +#: ./templates/Organisations/add.php:18 +#: ./templates/Organisations/add.php:30 +msgid "Nuova Organizzazione" +msgstr "New Organisation" + +#: ./templates/Organisations/add.php:39 +#: ./templates/Organisations/edit.php:43 +#: ./templates/Organisations/view.php:38 +msgid "Tipo organizzazione" +msgstr "Organisation type" + +#: ./templates/Organisations/add.php:46 +#: ./templates/Organisations/edit.php:50 +#: ./templates/Organisations/view.php:45 +msgid "Posizione Organizzazione" +msgstr "Organisation Location" + +#: ./templates/Organisations/edit.php:18 +#: ./templates/Organisations/view.php:18 +#: ./templates/Organisations/view.php:29 +msgid "Dettaglio Organizzazione" +msgstr "Organisation Details" + +#: ./templates/Organisations/edit.php:23 +#: ./templates/Organisations/edit.php:34 +msgid "Modifica Organizzazione" +msgstr "Edit Organisation" + +#: ./templates/Organisations/index.php:23 +msgid "Lista delle {0} Organizzazioni" +msgstr "List of {0} Organisations" + +#: ./templates/Organisations/index.php:23 +#: ./templates/Users/index.php:23 +msgid "{0} su {1}" +msgstr "{0} out of {1}" + +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +msgid "Sei sicuro che vuoi cancellare l'organizzazione \"{0}\" ?" +msgstr "Are you sure you want to delete the organisation \"{0}\" ?" + +#: ./templates/Phones/add.php:40 +msgid "Aggiungi Telefono per {0} \"{1}\"" +msgstr "Add Phone for {0} \"{1}\"" + +#: ./templates/Phones/edit.php:28 +msgid "Modifica Telefono" +msgstr "Edit Phone" + +#: ./templates/Phones/edit.php:40 +msgid "Modifica Telefono per {0} \"{1}\"" +msgstr "Edit Phone for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:40 +msgid "Aggiungi Chat Telegram per {0} \"{1}\"" +msgstr "Add Telegram Chat for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:47 +#: ./templates/TelegramChats/edit.php:47 +msgid "Chat Telegram ID" +msgstr "Telegram Chat ID" + +#: ./templates/TelegramChats/edit.php:28 +msgid "Modifica Chat Telegram" +msgstr "Edit Telegram Chat" + +#: ./templates/TelegramChats/edit.php:40 +msgid "Modifica Chat Telegram per {0} \"{1}\"" +msgstr "Edit Telegram Chat for {0} \"{1}\"" + +#: ./templates/Users/add.php:13 +#: ./templates/Users/edit.php:13 +#: ./templates/Users/index.php:13 +#: ./templates/Users/view.php:13 +msgid "Lista Utenti" +msgstr "Users List" + +#: ./templates/Users/add.php:18 +#: ./templates/Users/add.php:31 +msgid "Nuovo Utente" +msgstr "New User" + +#: ./templates/Users/add.php:38 +#: ./templates/Users/edit.php:43 +#: ./templates/Users/view.php:41 +msgid "Nome utente" +msgstr "Username" + +#: ./templates/Users/add.php:39 +#: ./templates/Users/edit.php:44 +msgid "Password" +msgstr "Password" + +#: ./templates/Users/add.php:42 +#: ./templates/Users/edit.php:47 +#: ./templates/Users/view.php:47 +msgid "Codice Fiscale" +msgstr "Tax ID code" + +#: ./templates/Users/add.php:43 +#: ./templates/Users/edit.php:48 +#: ./templates/Users/view.php:49 +msgid "Data di nascita" +msgstr "Date of birth" + +#: ./templates/Users/add.php:44 +#: ./templates/Users/edit.php:49 +#: ./templates/Users/view.php:51 +msgid "Luogo di nascita" +msgstr "Birth place" + +#: ./templates/Users/add.php:45 +#: ./templates/Users/edit.php:50 +#: ./templates/Users/view.php:53 +msgid "Sesso" +msgstr "Gender" + +#: ./templates/Users/add.php:47 +#: ./templates/Users/edit.php:52 +#: ./templates/Users/view.php:57 +msgid "Città" +msgstr "City" + +#: ./templates/Users/add.php:49 +#: ./templates/Users/edit.php:54 +#: ./templates/Users/view.php:61 +msgid "Lingua preferita" +msgstr "Favourite language" + +#: ./templates/Users/add.php:51 +#: ./templates/Users/edit.php:56 +msgid "Foto del profilo (solo jpeg di dimensioni 160x160!)" +msgstr "Photo (160x160 sized jpeg only!)" + +#: ./templates/Users/choose_new_password.php:4 +msgid "Imposta una nuova password" +msgstr "Set a new password" + +#: ./templates/Users/choose_new_password.php:5 +msgid "Digita la nuova password" +msgstr "Enter the new password" + +#: ./templates/Users/choose_new_password.php:6 +msgid "Ridigita la nuova password" +msgstr "Retype the previous entered password" + +#: ./templates/Users/edit.php:18 +#: ./templates/Users/view.php:18 +msgid "Dettaglio Utente" +msgstr "User Details" + +#: ./templates/Users/edit.php:23 +#: ./templates/Users/edit.php:36 +msgid "Modifica Utente" +msgstr "Edit User" + +#: ./templates/Users/index.php:23 +msgid "Lista dei {0} Utenti" +msgstr "List of {0} Users" + +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Sei sicuro che vuoi cancellare l'utente \"{0}\" ?" +msgstr "Are you sure you wanto to delete the user \"{0}\" ?" + +#: ./templates/Users/login.php:4 +msgid "Accedi" +msgstr "Gain access" + +#: ./templates/Users/login.php:8 +msgid "Login" +msgstr "Login" + +#: ./templates/Users/password_recovery.php:4 +msgid "Inserisci un indirizzo email associato alla tua utenza" +msgstr "Insert an email that is currently associated with your account" + +#: ./templates/Users/password_recovery.php:7 +msgid "Richiedi reset password" +msgstr "Request password reset" + +#: ./templates/Users/view.php:30 +msgid "Informazioni Utente" +msgstr "User Informations" + +#: ./templates/Users/view.php:34 +msgid "Elimina foto" +msgstr "Delete photo" + +#: ./templates/Users/view.php:34 +msgid "Sei sicuro che vuoi eliminare la foto ?" +msgstr "Are you sure you want to delete the photo ?" + +#: ./templates/Users/view.php:62 +msgid "Non specificata" +msgstr "Not specified" + +#: ./templates/Users/view.php:67 +msgid "Recapiti:" +msgstr "Contacts" + +#: ./templates/cell/FilterInput/display.php:9 +#: ./templates/element/attachments.php:127 +msgid "Rimuovi" +msgstr "Remove" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:113 +msgid "Filtri attivi" +msgstr "Filters applied" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:116 +msgid "Filtri disattivati" +msgstr "No Filters applied" + +#: ./templates/cell/Filters/display.php:15 +msgid "Aggiungi un filtro" +msgstr "Add a filter" + +#: ./templates/cell/Filters/display.php:34 +#: ./templates/cell/Filters/display.php:55 +msgid "Applica" +msgstr "Apply" + +#: ./templates/cell/Filters/display.php:39 +msgid "Reset" +msgstr "Reset" + +#: ./templates/cell/Filters/display.php:56 +msgid "Annulla" +msgstr "Cancel" + +#: ./templates/cell/Filters/display.php:58 +msgid "A" +msgstr "TO" + +#: ./templates/cell/Filters/display.php:59 +msgid "Dal Al" +msgstr "From To" + +#: ./templates/cell/Filters/display.php:60 +#: ./templates/cell/Filters/display.php:87 +msgid "Oggi" +msgstr "Today" + +#: ./templates/cell/Filters/display.php:62 +msgid "Dom" +msgstr "Sun" + +#: ./templates/cell/Filters/display.php:63 +msgid "Lun" +msgstr "Mon" + +#: ./templates/cell/Filters/display.php:64 +msgid "Mar" +msgstr "Tue" + +#: ./templates/cell/Filters/display.php:65 +msgid "Mer" +msgstr "Wed" + +#: ./templates/cell/Filters/display.php:66 +msgid "Gio" +msgstr "Thu" + +#: ./templates/cell/Filters/display.php:67 +msgid "Ven" +msgstr "Fri" + +#: ./templates/cell/Filters/display.php:68 +msgid "Sab" +msgstr "Sat" + +#: ./templates/cell/Filters/display.php:71 +msgid "Gennaio" +msgstr "January" + +#: ./templates/cell/Filters/display.php:72 +msgid "Febbraio" +msgstr "February" + +#: ./templates/cell/Filters/display.php:73 +msgid "Marzo" +msgstr "March" + +#: ./templates/cell/Filters/display.php:74 +msgid "Aprile" +msgstr "April" + +#: ./templates/cell/Filters/display.php:75 +msgid "Maggio" +msgstr "May" + +#: ./templates/cell/Filters/display.php:76 +msgid "Giugno" +msgstr "June" + +#: ./templates/cell/Filters/display.php:77 +msgid "Luglio" +msgstr "July" + +#: ./templates/cell/Filters/display.php:78 +msgid "Agosto" +msgstr "August" + +#: ./templates/cell/Filters/display.php:79 +msgid "Settembre" +msgstr "September" + +#: ./templates/cell/Filters/display.php:80 +msgid "Ottobre" +msgstr "October" + +#: ./templates/cell/Filters/display.php:81 +msgid "Novembre" +msgstr "November" + +#: ./templates/cell/Filters/display.php:82 +msgid "Dicembre" +msgstr "December" + +#: ./templates/cell/Filters/display.php:88 +msgid "Ieri" +msgstr "Yesterday" + +#: ./templates/cell/Filters/display.php:89 +msgid "Questa settimana" +msgstr "This week" + +#: ./templates/cell/Filters/display.php:90 +msgid "Questo mese" +msgstr "This month" + +#: ./templates/cell/Filters/display.php:91 +msgid "Lo scorso mese" +msgstr "Last month" + +#: ./templates/cell/Filters/display.php:92 +msgid "Ultimi 7 giorni" +msgstr "Last 7 days" + +#: ./templates/cell/Filters/display.php:93 +msgid "Ultimi 15 giorni" +msgstr "Last 15 days" + +#: ./templates/cell/Filters/display.php:94 +msgid "Ultimi 30 giorni" +msgstr "Last 30 days" + +#: ./templates/cell/Filters/display.php:131 +msgid "Errore durante il recupero del filtro selezionato. Riprovare di nuovo" +msgstr "Error trying to retrieve the selected filter. Pleas try again" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:118 +#: ./templates/element/Map.php:122 +msgid "OpenStreetMap ONLINE" +msgstr "OpenStreetMap ONLINE" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:127 +#: ./templates/element/Map.php:131 +msgid "OpenStreetMap OFFLINE" +msgstr "OpenStreetMap OFFLINE" + +#: ./templates/element/Map.php:312 +#: ./templates/element/Map.php:541 +msgid "Indirizzo non trovato o fuori dall'area di competenza" +msgstr "Address not found or out of the platform configured bounding box" + +#: ./templates/element/Map.php:530 +msgid "Punto alle coordinate (EPSG:4326) Latitudine:" +msgstr "Point of coordinates (EPSG:4326) Latitude:" + +#: ./templates/element/Map.php:530 +msgid "Longitudine:" +msgstr "Longitude:" + +#: ./templates/element/MapCore/MapPrimitives.php:10 +msgid "Scegli un risultato:" +msgstr "Pick a result" + +#: ./templates/element/MapCore/MapPrimitives.php:30 +msgid "Inserisci un indirizzo o le coordinate (in formato EPSG:4326)" +msgstr "Insert an address or coordinates (EPSG:4326)" + +#: ./templates/element/MapCore/MapPrimitives.php:31 +msgid "Cerca un indirizzo" +msgstr "Look up for an address" + +#: ./templates/element/MapCore/MapPrimitives.php:36 +msgid "Inserisci un punto in mappa" +msgstr "Insert a point on map" + +#: ./templates/element/MapCore/MapPrimitives.php:41 +msgid "Inserisci un poligono in mappa" +msgstr "Draw a polygon on map" + +#: ./templates/element/MapCore/MapPrimitives.php:46 +msgid "Inserisci un cerchio in mappa" +msgstr "Draw a circle on map" + +#: ./templates/element/MapCore/MapPrimitives.php:51 +msgid "Cancella una geometria" +msgstr "Delete a geometry" + +#: ./templates/element/attachmentPreview.php:16 +msgid "Il tuo browser non supporta HTML5 video tag. Prova ad aggiornare il tuo browser." +msgstr "Your browser doesn't seem to support HTML5 video tag. Please try and update your browser to a more recent version." + +#: ./templates/element/attachmentPreview.php:35 +msgid "Anteprima non disponibile" +msgstr "Preview not available" + +#: ./templates/element/attachments.php:30 +msgid "di tipo: \"{0}\"" +msgstr "of type \"{0}\"" + +#: ./templates/element/attachments.php:39 +msgid "Mostra allegati correlati" +msgstr "Show also linked attachments" + +#: ./templates/element/attachments.php:48 +msgid "Allega un file " +msgstr "Attach a file" + +#: ./templates/element/attachments.php:48 +msgid "Allega files " +msgstr "Attach files" + +#: ./templates/element/attachments.php:54 +msgid "Allega file pubblico " +msgstr "Attach public file" + +#: ./templates/element/attachments.php:54 +msgid "Allega un file privato " +msgstr "Attach a private file" + +#: ./templates/element/attachments.php:54 +msgid "Allega files privati " +msgstr "Attach private files " + +#: ./templates/element/attachments.php:58 +msgid "Allega files..." +msgstr "Attach files..." + +#: ./templates/element/attachments.php:65 +msgid "Allega files {1} {0}" +msgstr "Attach files {1} {0}" + +#: ./templates/element/attachments.php:118 +msgid "latitudine" +msgstr "latitude" + +#: ./templates/element/attachments.php:119 +msgid "longitudine" +msgstr "longitude" + +#: ./templates/layout/error.php:38 +msgid "Back" +msgstr "Back" + +#: ./templates/plugin/AdminLTE/element/aside-control-sidebar.php:4 +msgid "Notifiche" +msgstr "Notifications" + +#: ./templates/plugin/AdminLTE/element/footer.php:6 +msgid "Versione" +msgstr "Version" + +#: ./templates/plugin/AdminLTE/element/footer.php:9 +msgid "Tutti i diritti riservati" +msgstr "All rights reserved" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:67 +msgid "Nuove notifiche: {0}" +msgstr "New notifications: {0}" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:91 +msgid "Segna tutte le notifiche come lette" +msgstr "Mark all new notifications as read" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:121 +msgid "Esci" +msgstr "Logout" + diff --git a/idrocap_wa/resources/locales/en/previous_default.po b/idrocap_wa/resources/locales/en/previous_default.po new file mode 100644 index 0000000..bd63efb --- /dev/null +++ b/idrocap_wa/resources/locales/en/previous_default.po @@ -0,0 +1,1709 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2023-03-03 14:35+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./src/Controller/Api/AttachmentsController.php:36 +#: ./src/Controller/AttachmentsController.php:38 +#: ./src/Controller/AttachmentsController.php:68 +msgid "Allegato non trovato" +msgstr "Attachment not found" + +#: ./src/Controller/Api/AttachmentsController.php:37 +#: ./src/Controller/AttachmentsController.php:39 +#: ./src/Controller/AttachmentsController.php:69 +msgid "Non hai i permessi necessari per visionare l'allegato" +msgstr "You do not have permission to view the attachment" + +#: ./src/Controller/Api/OrganisationsController.php:104 +msgid "Organizzazione non trovata!" +msgstr "Organisation not found!" + +#: ./src/Controller/Api/UsersController.php:160 +msgid "Utente non trovato!" +msgstr "User not found!" + +#: ./src/Controller/AppController.php:95 +msgid "SYSADMIN" +msgstr "SYSADMIN" + +#: ./src/Controller/AppController.php:99 +#: ./templates/Capabilities/index.php:13 +#: ./templates/Groups/handle_capabilities.php:23 +#: ./templates/Groups/view.php:42 +msgid "Gestione competenze" +msgstr "Handle capabilities" + +#: ./src/Controller/AppController.php:104 +msgid "Test notifiche" +msgstr "Test notification system" + +#: ./src/Controller/AppController.php:107 +msgid "Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?" +msgstr "Notifications will be sent to all users and organisations that have at least one notification enabled contact! Are you sure you want to proceed ?" + +#: ./src/Controller/CapabilitiesController.php:24 +#: ./src/Controller/CapabilitiesController.php:54 +#: ./src/Controller/CapabilitiesController.php:97 +#: ./src/Controller/CapabilitiesController.php:135 +#: ./src/Controller/CapabilitiesController.php:177 +#: ./src/Controller/GroupsController.php:31 +#: ./src/Controller/GroupsController.php:54 +#: ./src/Controller/GroupsController.php:92 +#: ./src/Controller/GroupsController.php:112 +#: ./src/Controller/GroupsController.php:136 +#: ./src/Controller/GroupsController.php:160 +#: ./src/Controller/GroupsController.php:183 +#: ./src/Controller/OrganisationsController.php:32 +#: ./src/Controller/OrganisationsController.php:60 +#: ./src/Controller/OrganisationsController.php:109 +#: ./src/Controller/OrganisationsController.php:131 +#: ./src/Controller/OrganisationsController.php:155 +#: ./src/Controller/OrganisationsController.php:181 +#: ./src/Controller/UsersController.php:38 +#: ./src/Controller/UsersController.php:70 +#: ./src/Controller/UsersController.php:113 +#: ./src/Controller/UsersController.php:119 +#: ./src/Controller/UsersController.php:136 +#: ./src/Controller/UsersController.php:177 +#: ./src/Controller/UsersController.php:211 +#: ./src/Controller/UsersController.php:216 +msgid "Non hai i permessi necessari" +msgstr "You do not have needed permissions" + +#: ./src/Controller/CapabilitiesController.php:79 +msgid "Competenza \"{0}\" nascosta con successo!" +msgstr "Capability \"{0}\" successfully hidden!" + +#: ./src/Controller/CapabilitiesController.php:82 +msgid "Errore durante il tentativo di nascondere la Competenza \"{0}\"!" +msgstr "Error trying to hide the capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:117 +msgid "Competenza \"{0}\" resa visibile con successo!" +msgstr "Capability \"{0}\" successfully set unhidden!" + +#: ./src/Controller/CapabilitiesController.php:120 +msgid "Errore durante il tentativo di rendere visibile la Competenza \"{0}\"!" +msgstr "Error trying to set the capability \"{0}\" unhidden!" + +#: ./src/Controller/CapabilitiesController.php:159 +msgid "Competenza \"{0}\" cancellata con successo!" +msgstr "Capability \"{0}\" successfully deleted!" + +#: ./src/Controller/CapabilitiesController.php:162 +msgid "Errore durante la cancellazione della Competenza \"{0}\"!" +msgstr "Error trying to delete the Capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:197 +msgid "Competenza \"{0}\" ripristinata con successo!" +msgstr "Capability \"{0}\" successfully restored!" + +#: ./src/Controller/CapabilitiesController.php:200 +msgid "Errore durante il ripristino della Competenza \"{0}\"!" +msgstr "Error trying to restore the capability \"{0}\"!" + +#: ./src/Controller/DeliveriesController.php:27 +#: ./src/Controller/DeliveriesController.php:125 +#: ./src/Controller/EmailsController.php:25 +#: ./src/Controller/EmailsController.php:64 +#: ./src/Controller/FaxesController.php:25 +#: ./src/Controller/FaxesController.php:64 +#: ./src/Controller/MobilePhonesController.php:26 +#: ./src/Controller/MobilePhonesController.php:65 +#: ./src/Controller/PhonesController.php:25 +#: ./src/Controller/PhonesController.php:64 +#: ./src/Controller/TelegramChatsController.php:25 +#: ./src/Controller/TelegramChatsController.php:63 +msgid "Gestione recapiti non prevista per questa tipologia di oggetto" +msgstr "Contacts management is not expected for this type of object" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questa organizzazione" +msgstr "this organisation" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questo utente" +msgstr "this user" + +#: ./src/Controller/DeliveriesController.php:30 +msgid "Non hai i permessi per visualizzare i recapiti per {0}" +msgstr "You do not have permission to view contacts for {0}" + +#: ./src/Controller/DeliveriesController.php:128 +msgid "Non hai i permessi per eliminare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to delete contacts of this type for {0}" + +#: ./src/Controller/DeliveriesController.php:134 +#: ./src/Model/Entity/Actor.php:87 +msgid "Cellulare ({0}): {1}" +msgstr "Mobile Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:137 +#: ./src/Model/Entity/Actor.php:97 +msgid "Fax ({0}): {1}" +msgstr "Fax ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:140 +#: ./src/Model/Entity/Actor.php:107 +msgid "Email ({0}): {1}" +msgstr "Email ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:143 +#: ./src/Model/Entity/Actor.php:117 +msgid "Telefono ({0}): {1}" +msgstr "Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:146 +#: ./src/Model/Entity/Actor.php:127 +msgid "Telegram Chat ID: {0}" +msgstr "Telegram Chat ID: {0}" + +#: ./src/Controller/DeliveriesController.php:154 +msgid "Il recapito \"{0}\" è stato cancellato con successo" +msgstr "Contact \"{0}\" successfully deleted" + +#: ./src/Controller/DeliveriesController.php:156 +msgid "Errore durante la cancellazione del recapito {0}. Riprovare di nuovo." +msgstr "Error trying to delete contact {0}. Please try again." + +#: ./src/Controller/EmailsController.php:27 +#: ./src/Controller/FaxesController.php:27 +#: ./src/Controller/MobilePhonesController.php:28 +#: ./src/Controller/PhonesController.php:27 +#: ./src/Controller/TelegramChatsController.php:27 +msgid "Non hai i permessi per aggiungere i recapiti di questo tipo per {0}" +msgstr "You do not have permission to add this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:39 +msgid "L'Email è stata aggiunta con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:43 +msgid "Errore durante l'aggiunta dell'Email: {0}" +msgstr "Error trying adding Email: {0}" + +#: ./src/Controller/EmailsController.php:66 +#: ./src/Controller/FaxesController.php:66 +#: ./src/Controller/MobilePhonesController.php:67 +#: ./src/Controller/PhonesController.php:66 +#: ./src/Controller/TelegramChatsController.php:65 +msgid "Non hai i permessi per modificare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to edit this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:71 +msgid "L'Email è stata modificata con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:75 +msgid "Errore durante la modifica dell'Email. Riprovare di nuovo" +msgstr "Error trying to edit Email contact. Please try again" + +#: ./src/Controller/FaxesController.php:39 +msgid "Il Fax è stato aggiunto con successo." +msgstr "Fax successfully added." + +#: ./src/Controller/FaxesController.php:43 +msgid "Errore durante l'aggiunta del Fax: {0}" +msgstr "Error trying to add Fax: {0}" + +#: ./src/Controller/FaxesController.php:71 +msgid "Il Fax è stato modificato con successo." +msgstr "Fax successfully updated." + +#: ./src/Controller/FaxesController.php:75 +msgid "Errore durante la modifica del Fax. Riprovare di nuovo" +msgstr "Error trying to edit Fax. Please try again" + +#: ./src/Controller/GroupsController.php:57 +#: ./src/Controller/OrganisationsController.php:63 +#: ./templates/Capabilities/index.php:41 +#: ./templates/Deliveries/index.php:49 +#: ./templates/Deliveries/index.php:91 +#: ./templates/Deliveries/index.php:133 +#: ./templates/Deliveries/index.php:175 +#: ./templates/Emails/add.php:48 +#: ./templates/Emails/edit.php:48 +#: ./templates/Faxes/add.php:48 +#: ./templates/Faxes/edit.php:48 +#: ./templates/Groups/add.php:38 +#: ./templates/Groups/edit.php:43 +#: ./templates/Groups/index.php:31 +#: ./templates/Groups/view.php:35 +#: ./templates/MobilePhones/add.php:48 +#: ./templates/MobilePhones/edit.php:48 +#: ./templates/Organisations/index.php:29 +#: ./templates/Phones/add.php:48 +#: ./templates/Phones/edit.php:48 +msgid "Descrizione" +msgstr "Description" + +#: ./src/Controller/GroupsController.php:58 +#: ./templates/Groups/add.php:39 +#: ./templates/Groups/edit.php:44 +#: ./templates/Groups/index.php:32 +#: ./templates/Groups/view.php:37 +msgid "Profilo Default" +msgstr "Default Profile" + +#: ./src/Controller/GroupsController.php:59 +#: ./templates/Groups/add.php:40 +#: ./templates/Groups/edit.php:45 +#: ./templates/Groups/index.php:33 +#: ./templates/Groups/view.php:39 +msgid "Profilo Amministratore" +msgstr "Admin Profile" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "SI" +msgstr "YES" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "NO" +msgstr "NO" + +#: ./src/Controller/GroupsController.php:118 +msgid "Profilo Utente creato con successo." +msgstr "User Profile successfully created." + +#: ./src/Controller/GroupsController.php:122 +msgid "Errore durante la creazione del Profilo Utente: {0}" +msgstr "Error trying to create User Profile: {0}" + +#: ./src/Controller/GroupsController.php:142 +#: ./src/Controller/GroupsController.php:206 +msgid "Profilo Utente \"{0}\" modificato con successo." +msgstr "User Profile \"{0}\" successfully updated." + +#: ./src/Controller/GroupsController.php:146 +#: ./src/Controller/GroupsController.php:209 +msgid "Errore durante la modifica del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/GroupsController.php:166 +msgid "Il Profilo Utente \"{0}\" è stato cancellato con successo" +msgstr "\"{0}\" User Profile successfully deleted" + +#: ./src/Controller/GroupsController.php:168 +msgid "Errore durante la cancellazione del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/MapsController.php:131 +msgid "Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}" +msgstr "Point at coordinates (EPSG:4326) Latitude: {0}, Longitude: {1}" + +#: ./src/Controller/MobilePhonesController.php:40 +msgid "Il Cellulare è stato aggiunto con successo." +msgstr "Mobile Phone contact successfully created." + +#: ./src/Controller/MobilePhonesController.php:44 +msgid "Errore durante l'aggiunta del Cellulare: {0}" +msgstr "Error trying to create Mobile Phone: {0}" + +#: ./src/Controller/MobilePhonesController.php:72 +msgid "Il Cellulare è stato modificato con successo." +msgstr "Mobile Phone successfully updated." + +#: ./src/Controller/MobilePhonesController.php:76 +msgid "Errore durante la modifica del Cellulare. Riprovare di nuovo" +msgstr "Error trying to edit Mobile Phone. Please try again" + +#: ./src/Controller/NotificationsController.php:51 +msgid "Errore durante la cancellazione della notifica: " +msgstr "Error trying to delete the notification: " + +#: ./src/Controller/OrganisationsController.php:64 +#: ./templates/Organisations/add.php:38 +#: ./templates/Organisations/edit.php:42 +#: ./templates/Organisations/index.php:30 +#: ./templates/Organisations/view.php:37 +msgid "Acronimo" +msgstr "Acronym" + +#: ./src/Controller/OrganisationsController.php:65 +#: ./templates/Organisations/index.php:31 +msgid "Tipologia" +msgstr "Typology" + +#: ./src/Controller/OrganisationsController.php:66 +#: ./templates/Maps/index.php:131 +#: ./templates/Organisations/add.php:140 +#: ./templates/Organisations/add.php:159 +#: ./templates/Organisations/edit.php:63 +#: ./templates/Organisations/index.php:32 +#: ./templates/Organisations/view.php:52 +#: ./templates/Users/add.php:46 +#: ./templates/Users/edit.php:51 +#: ./templates/Users/view.php:55 +msgid "Indirizzo" +msgstr "Address" + +#: ./src/Controller/OrganisationsController.php:67 +#: ./templates/Maps/index.php:120 +#: ./templates/Organisations/add.php:129 +#: ./templates/Organisations/add.php:161 +#: ./templates/Organisations/edit.php:65 +#: ./templates/Organisations/index.php:34 +#: ./templates/Organisations/view.php:54 +msgid "Comune" +msgstr "District" + +#: ./src/Controller/OrganisationsController.php:68 +#: ./templates/Organisations/add.php:160 +#: ./templates/Organisations/edit.php:64 +#: ./templates/Organisations/index.php:33 +#: ./templates/Organisations/view.php:53 +#: ./templates/Users/add.php:48 +#: ./templates/Users/edit.php:53 +#: ./templates/Users/view.php:59 +msgid "CAP" +msgstr "ZIP code" + +#: ./src/Controller/OrganisationsController.php:69 +#: ./templates/Maps/index.php:109 +#: ./templates/Organisations/add.php:118 +#: ./templates/Organisations/add.php:162 +#: ./templates/Organisations/edit.php:66 +#: ./templates/Organisations/index.php:35 +#: ./templates/Organisations/view.php:55 +msgid "Provincia" +msgstr "Province" + +#: ./src/Controller/OrganisationsController.php:70 +#: ./src/Controller/UsersController.php:76 +#: ./templates/Organisations/index.php:36 +#: ./templates/Organisations/view.php:56 +#: ./templates/Users/index.php:32 +msgid "Recapiti" +msgstr "Contacts" + +#: ./src/Controller/OrganisationsController.php:137 +msgid "Organizzazione creata con successo." +msgstr "Organisation successfully created." + +#: ./src/Controller/OrganisationsController.php:141 +msgid "Errore durante la creazione dell'organizzazione: {0}" +msgstr "Error trying to create the organisation: {0}" + +#: ./src/Controller/OrganisationsController.php:163 +msgid "Organizzazione \"{0}\" modificata con successo." +msgstr "Organisation \"{0}\" successfully updated." + +#: ./src/Controller/OrganisationsController.php:167 +msgid "Errore durante la modifica dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the organisation \"{0}\". Please try again." + +#: ./src/Controller/OrganisationsController.php:188 +msgid "Impossibile eliminare l'organizzazione \"{0}\". Ci sono {1} utenti collegati ad essa." +msgstr "Unable to delete the organisation \"{0}\". There are {1} belonging users." + +#: ./src/Controller/OrganisationsController.php:193 +msgid "L'organizzazione \"{0}\" è stata cancellata con successo" +msgstr "Organisation \"{0}\" successfully deleted" + +#: ./src/Controller/OrganisationsController.php:195 +msgid "Errore durante la cancellazione dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the organisation \"{0}\". Please try again." + +#: ./src/Controller/PhonesController.php:39 +msgid "Il Telefono è stato aggiunto con successo." +msgstr "Phone successfully created." + +#: ./src/Controller/PhonesController.php:43 +msgid "Errore durante l'aggiunta del Telefono: {0}" +msgstr "Error trying to create Phone: {0}" + +#: ./src/Controller/PhonesController.php:71 +msgid "Il Telefono è stato modificato con successo." +msgstr "Phone successfully updated." + +#: ./src/Controller/PhonesController.php:75 +msgid "Errore durante la modifica del Telefono. Riprovare di nuovo" +msgstr "Error trying to edit Phone. Please try again" + +#: ./src/Controller/TelegramChatsController.php:39 +msgid "La Chat Telegram è stata aggiunta con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:43 +msgid "Errore durante l'aggiunta della Chat Telegram: {0}" +msgstr "Error trying to create Telegram Chat: {0}" + +#: ./src/Controller/TelegramChatsController.php:70 +msgid "La Chat Telegram è stata modificata con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:74 +msgid "Errore durante la modifica della Chat Telegram. Riprovare di nuovo" +msgstr "Error trying to edit Telegram Chat. Please try again" + +#: ./src/Controller/UsersController.php:73 +#: ./templates/Users/add.php:41 +#: ./templates/Users/edit.php:46 +#: ./templates/Users/index.php:29 +#: ./templates/Users/view.php:45 +msgid "Cognome" +msgstr "Surname" + +#: ./src/Controller/UsersController.php:74 +#: ./templates/ControllableObjects/get_attachments.php:59 +#: ./templates/Organisations/add.php:37 +#: ./templates/Organisations/edit.php:41 +#: ./templates/Organisations/view.php:36 +#: ./templates/Users/add.php:40 +#: ./templates/Users/edit.php:45 +#: ./templates/Users/index.php:30 +#: ./templates/Users/view.php:43 +msgid "Nome" +msgstr "Name" + +#: ./src/Controller/UsersController.php:75 +#: ./templates/Users/index.php:31 +msgid "Username" +msgstr "Username" + +#: ./src/Controller/UsersController.php:77 +#: ./templates/Users/add.php:52 +#: ./templates/Users/edit.php:57 +#: ./templates/Users/index.php:33 +#: ./templates/Users/view.php:65 +msgid "Profili" +msgstr "Profiles" + +#: ./src/Controller/UsersController.php:78 +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +#: ./templates/Users/add.php:50 +#: ./templates/Users/edit.php:55 +#: ./templates/Users/index.php:34 +#: ./templates/Users/view.php:63 +msgid "Organizzazione" +msgstr "Organisation" + +#: ./src/Controller/UsersController.php:156 +msgid "Utente creato con successo." +msgstr "User successfully created." + +#: ./src/Controller/UsersController.php:160 +msgid "Errore durante la creazione dell'utente: {0}" +msgstr "Error trying to create user: {0}" + +#: ./src/Controller/UsersController.php:190 +msgid "Utente \"{0}\" modificato con successo." +msgstr "User \"{0}\" successfully updated." + +#: ./src/Controller/UsersController.php:194 +msgid "Errore durante la modifica dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:219 +msgid "L'utente \"{0}\" è stato cancellato con successo" +msgstr "User \"{0}\" successfully deleted" + +#: ./src/Controller/UsersController.php:221 +msgid "Errore durante la cancellazione dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:244 +msgid "Ho dimenticato la mia password" +msgstr "I forgot my password" + +#: ./src/Controller/UsersController.php:256 +msgid "Logout eseguito con successo." +msgstr "Successfully logged out." + +#: ./src/Controller/UsersController.php:294 +msgid "Inserire un indirizzo email valido!" +msgstr "Insert a valid email address!" + +#: ./src/Controller/UsersController.php:306 +msgid "A breve riceverai un'email all'indirizzo \"{0}\" con le istruzioni per eseguire il reset della password per il tuo account con username \"{1}\"." +msgstr "You will receive shortly an email at \"{0}\" with the instructions to reset the password for your account with username \"{1}\"." + +#: ./src/Controller/UsersController.php:311 +msgid "L'indirizzo email inserito non risulta presente" +msgstr "The email address you inserted is not valid or does not exists" + +#: ./src/Controller/UsersController.php:316 +#: ./src/Controller/UsersController.php:364 +msgid "Ritorna al login" +msgstr "Back to login" + +#: ./src/Controller/UsersController.php:332 +msgid "Impossibile completare la procedura di recupero password." +msgstr "Unable to complete reset password procedure. Please try again." + +#: ./src/Controller/UsersController.php:355 +msgid "Impossibile cambiare la password" +msgstr "Unable to change the password" + +#: ./src/Controller/UsersController.php:359 +msgid "La nuova password non è valida e/o le 2 password non coincidono" +msgstr "Either the new password is invalid or the two passwords don't match" + +#: ./src/Controller/UsersController.php:397 +msgid "Errore durante l'eliminazione della foto utente!" +msgstr "Error trying to delete the user photo!" + +#: ./src/Controller/UsersController.php:399 +msgid "Foto utente eliminata con successo" +msgstr "User photo successfully deleted" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:41 +msgid "Test Test Test" +msgstr "Test Test Test" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:43 +msgid "Hai ricevuto questo messaggio di test perchè sei registrato/a sulla piattaforma {0} ed hai almeno un recapito abilitato alla ricezione delle notifiche" +msgstr "You're receiving this message because you are a registered user to {0} platform and you have at least one notification enabled contact" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:46 +msgid "Recupero password {0}" +msgstr "{0} password reset" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:50 +msgid "Hai ricevuto questo messaggio perchè sei registrato/a sulla piattaforma {0} ed è stata richiesta la procedura di recupero credenziali per il tuo account. Se non hai richiesto tale procedura ti preghiamo di ignorare questo messaggio. Per accedere a {0} utilizza il seguente username: \" {1} \" . Clicca sul seguente link per impostare una nuova password " +msgstr "You're receiving this message because you are a registered user to {0} platform and you requested a password reset for your account. Plese disregard this message if you didn't request it or if you changed your mind. Please use the following username to gain access to your account: \" {1} \" . Follow this link to reset your password instead " + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:53 +msgid "{0} mancante" +msgstr "Missing \"{0}\" notification code" + +#: ./src/Model/Behavior/AttachmentsBehavior.php:132 +msgid "L'allegato è obbligatorio!" +msgstr "The attachment is mandatory!" + +#: ./src/Model/Entity/ControllableObject.php:241 +msgid "Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The given coordinates used to georeferencing one or more attachments are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/EmailsTable.php:107 +msgid "Indirizzo email già presente a sistema!" +msgstr "Email address already exists!" + +#: ./src/Model/Table/FaxesTable.php:103 +msgid "Fax già presente a sistema!" +msgstr "Fax already exists!" + +#: ./src/Model/Table/MobilePhonesTable.php:107 +msgid "Cellulare già presente a sistema!" +msgstr "Mobile Phone already exists!" + +#: ./src/Model/Table/OrganisationsTable.php:169 +msgid "Le geometrie inserite per georeferenziare l'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The inserted geometries used to georeferenciate the organisation, are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/PhonesTable.php:99 +msgid "Telefono già presente a sistema!" +msgstr "Phone already exists!" + +#: ./src/Model/Table/PushNotificationsTable.php:97 +msgid "Non puoi associare nuovamente questo token allo stesso utente" +msgstr "You cannot use this push notification token again with this user" + +#: ./src/Model/Table/UsersTable.php:106 +msgid "La password deve contenere almeno {0} caratteri" +msgstr "The password must contain at least {0} characters" + +#: ./src/Model/Table/UsersTable.php:111 +msgid "La password deve contenere almeno {0} carattere/i maiuscolo/i" +msgstr "The password must contain at least {0} uppercase characters" + +#: ./src/Model/Table/UsersTable.php:117 +msgid "La password deve contenere almeno {0} numero/i" +msgstr "The password must contain at least {0} numbers" + +#: ./src/Model/Table/UsersTable.php:131 +msgid "La password deve contenere almeno {1} carattere/i speciale/i tra \"{0}\"" +msgstr "The password must contain at least {1} special characters to be chosen among \"{0}\"" + +#: ./src/Model/Table/UsersTable.php:256 +msgid "Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)" +msgstr "Error trying to save user photo. Please make sure that the photo you are trying to save is in the correct format and size (jpeg 160x160)" + +#: ./src/View/Cell/MapCell.php:182 +msgid "Geometrie disegnate" +msgstr "Drawn geometries" + +#: ./templates/Capabilities/index.php:9 +#: ./templates/Deliveries/index.php:9 +#: ./templates/Emails/add.php:9 +#: ./templates/Emails/edit.php:9 +#: ./templates/Faxes/add.php:9 +#: ./templates/Faxes/edit.php:9 +#: ./templates/Groups/add.php:9 +#: ./templates/Groups/edit.php:9 +#: ./templates/Groups/handle_capabilities.php:9 +#: ./templates/Groups/index.php:9 +#: ./templates/Groups/view.php:9 +#: ./templates/Maps/index.php:9 +#: ./templates/MobilePhones/add.php:9 +#: ./templates/MobilePhones/edit.php:9 +#: ./templates/Organisations/add.php:9 +#: ./templates/Organisations/edit.php:9 +#: ./templates/Organisations/index.php:9 +#: ./templates/Organisations/view.php:9 +#: ./templates/Phones/add.php:9 +#: ./templates/Phones/edit.php:9 +#: ./templates/TelegramChats/add.php:9 +#: ./templates/TelegramChats/edit.php:9 +#: ./templates/Users/add.php:9 +#: ./templates/Users/edit.php:9 +#: ./templates/Users/index.php:9 +#: ./templates/Users/view.php:9 +msgid "Configurazioni" +msgstr "Configurations" + +#: ./templates/Capabilities/index.php:24 +msgid "Lista delle competenze" +msgstr "Capabilities list" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca per descrizione competenza o codice o nome del gruppo di competenze" +msgstr "Search by capability description, code or capability group name" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca" +msgstr "Search" + +#: ./templates/Capabilities/index.php:42 +msgid "Codice" +msgstr "Code" + +#: ./templates/Capabilities/index.php:43 +msgid "Priorità" +msgstr "Priority" + +#: ./templates/Capabilities/index.php:44 +msgid "Gruppo" +msgstr "Group" + +#: ./templates/Capabilities/index.php:45 +#: ./templates/ControllableObjects/get_attachments.php:66 +#: ./templates/Deliveries/index.php:52 +#: ./templates/Deliveries/index.php:94 +#: ./templates/Deliveries/index.php:136 +#: ./templates/Deliveries/index.php:177 +#: ./templates/Deliveries/index.php:217 +#: ./templates/Groups/index.php:34 +#: ./templates/Organisations/index.php:37 +#: ./templates/Users/index.php:35 +msgid "Azioni" +msgstr "Actions" + +#: ./templates/Capabilities/index.php:57 +#: ./templates/Groups/handle_capabilities.php:57 +#: ./templates/Groups/handle_capabilities.php:58 +#: ./templates/Groups/handle_capabilities.php:59 +msgid "Competenza non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability not visible and not configurable by non SYSADMIN users" + +#: ./templates/Capabilities/index.php:58 +msgid "Competenza eliminata dal sistema" +msgstr "Capability successfully deleted" + +#: ./templates/Capabilities/index.php:67 +msgid "Nascondi" +msgstr "Hide" + +#: ./templates/Capabilities/index.php:67 +msgid "Mostra" +msgstr "Show" + +#: ./templates/Capabilities/index.php:68 +msgid "Ripristina" +msgstr "Restore" + +#: ./templates/Capabilities/index.php:68 +#: ./templates/Deliveries/index.php:63 +#: ./templates/Deliveries/index.php:105 +#: ./templates/Deliveries/index.php:147 +#: ./templates/Deliveries/index.php:187 +#: ./templates/Deliveries/index.php:227 +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Cancella" +msgstr "Delete" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Allegati presenti: {0}" +msgstr "Attachments: {0}" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Nessun Allegato presente" +msgstr "No Attachments" + +#: ./templates/ControllableObjects/get_attachments.php:60 +msgid "Georeferenziazione" +msgstr "Georeferencing" + +#: ./templates/ControllableObjects/get_attachments.php:62 +msgid "Dimensione" +msgstr "Size" + +#: ./templates/ControllableObjects/get_attachments.php:63 +msgid "Tipo" +msgstr "Type" + +#: ./templates/ControllableObjects/get_attachments.php:64 +msgid "Caricato il" +msgstr "Uploaded" + +#: ./templates/ControllableObjects/get_attachments.php:65 +#: ./templates/cell/Filters/display.php:57 +msgid "Da" +msgstr "From" + +#: ./templates/ControllableObjects/get_attachments.php:80 +msgid "File pubblico" +msgstr "Public file" + +#: ./templates/ControllableObjects/get_attachments.php:83 +msgid "File privato" +msgstr "Private file" + +#: ./templates/ControllableObjects/get_attachments.php:106 +msgid "Visualizza" +msgstr "View" + +#: ./templates/ControllableObjects/get_attachments.php:110 +msgid "Segna da eliminare" +msgstr "Mark as to be deleted" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come non rilevante" +msgstr "Mark as not relevant" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come rilevante" +msgstr "Mark as relevant" + +#: ./templates/Dashboard/index.php:16 +msgid "Jixel Dashboard" +msgstr "Jixel Dashboard" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Lista {0}" +msgstr "List {0}" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Organizzazioni" +msgstr "Organisations" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Utenti" +msgstr "Users" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Dettaglio {0}" +msgstr "{0} Details" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Utente" +msgstr "User" + +#: ./templates/Deliveries/index.php:23 +#: ./templates/Emails/add.php:23 +#: ./templates/Emails/edit.php:23 +#: ./templates/Faxes/add.php:23 +#: ./templates/Faxes/edit.php:23 +#: ./templates/MobilePhones/add.php:23 +#: ./templates/MobilePhones/edit.php:23 +#: ./templates/Organisations/view.php:69 +#: ./templates/Phones/add.php:23 +#: ./templates/Phones/edit.php:23 +#: ./templates/TelegramChats/add.php:23 +#: ./templates/TelegramChats/edit.php:23 +#: ./templates/Users/view.php:70 +msgid "Gestione recapiti" +msgstr "Contacts management" + +#: ./templates/Deliveries/index.php:31 +msgid "Recapiti associati a {0} \"{1}\"" +msgstr "Associated contacts to {0} \"{1}\"" + +#: ./templates/Deliveries/index.php:41 +msgid "Cellulare: {0}" +msgstr "Mobile Phone {0}" + +#: ./templates/Deliveries/index.php:50 +#: ./templates/MobilePhones/add.php:47 +#: ./templates/MobilePhones/edit.php:47 +msgid "Cellulare" +msgstr "Mobile Phone" + +#: ./templates/Deliveries/index.php:51 +#: ./templates/Deliveries/index.php:93 +#: ./templates/Deliveries/index.php:135 +#: ./templates/Deliveries/index.php:216 +#: ./templates/Emails/add.php:49 +#: ./templates/Emails/edit.php:49 +#: ./templates/Faxes/add.php:49 +#: ./templates/Faxes/edit.php:49 +#: ./templates/MobilePhones/add.php:49 +#: ./templates/MobilePhones/edit.php:49 +#: ./templates/TelegramChats/add.php:48 +#: ./templates/TelegramChats/edit.php:48 +msgid "Ricevi notifiche a questo recapito" +msgstr "Receive notifications at this contact" + +#: ./templates/Deliveries/index.php:62 +#: ./templates/Deliveries/index.php:104 +#: ./templates/Deliveries/index.php:146 +#: ./templates/Deliveries/index.php:186 +#: ./templates/Deliveries/index.php:226 +#: ./templates/Groups/index.php:45 +#: ./templates/Groups/view.php:43 +#: ./templates/Organisations/index.php:53 +#: ./templates/Organisations/view.php:70 +#: ./templates/Users/index.php:49 +#: ./templates/Users/view.php:71 +msgid "Modifica" +msgstr "Edit" + +#: ./templates/Deliveries/index.php:63 +msgid "Sei sicuro che vuoi cancellare il Cellulare \"{0}\" ?" +msgstr "Are you sure you want to delete the Mobile Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:73 +#: ./templates/MobilePhones/add.php:28 +msgid "Aggiungi Cellulare" +msgstr "Add Mobile Phone" + +#: ./templates/Deliveries/index.php:84 +msgid "Fax: {0}" +msgstr "Fax: {0}" + +#: ./templates/Deliveries/index.php:92 +#: ./templates/Faxes/add.php:47 +#: ./templates/Faxes/edit.php:47 +msgid "Fax" +msgstr "Fax" + +#: ./templates/Deliveries/index.php:105 +msgid "Sei sicuro che vuoi cancellare il Fax \"{0}\" ?" +msgstr "Are you sure you want to delete the Fax \"{0}\" ?" + +#: ./templates/Deliveries/index.php:115 +#: ./templates/Faxes/add.php:28 +msgid "Aggiungi Fax" +msgstr "Add Fax" + +#: ./templates/Deliveries/index.php:126 +msgid "Email: {0}" +msgstr "Email: {0}" + +#: ./templates/Deliveries/index.php:134 +#: ./templates/Emails/add.php:47 +#: ./templates/Emails/edit.php:47 +msgid "Email" +msgstr "Email" + +#: ./templates/Deliveries/index.php:147 +msgid "Sei sicuro che vuoi cancellare l'Email \"{0}\" ?" +msgstr "Are you sure you want to delete the Email \"{0}\" ?" + +#: ./templates/Deliveries/index.php:157 +#: ./templates/Emails/add.php:28 +msgid "Aggiungi Email" +msgstr "Add Email" + +#: ./templates/Deliveries/index.php:168 +msgid "Telefono: {0}" +msgstr "Phone {0}" + +#: ./templates/Deliveries/index.php:176 +#: ./templates/Phones/add.php:47 +#: ./templates/Phones/edit.php:47 +msgid "Telefono" +msgstr "Phone" + +#: ./templates/Deliveries/index.php:187 +msgid "Sei sicuro che vuoi cancellare il Telefono \"{0}\" ?" +msgstr "Are you sure you want to delete the Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:197 +#: ./templates/Phones/add.php:28 +msgid "Aggiungi Telefono" +msgstr "Add Phone" + +#: ./templates/Deliveries/index.php:208 +msgid "Chat Telegram: {0}" +msgstr "Telegram Chat: {0}" + +#: ./templates/Deliveries/index.php:215 +msgid "ID" +msgstr "ID" + +#: ./templates/Deliveries/index.php:227 +msgid "Sei sicuro che vuoi cancellare la Chat Telegram con ID \"{0}\" ?" +msgstr "Are you sure you want to delete the Telegram Chat with ID \"{0}\" ?" + +#: ./templates/Deliveries/index.php:237 +#: ./templates/TelegramChats/add.php:28 +msgid "Aggiungi Chat Telegram" +msgstr "Add Telegram Chat" + +#: ./templates/Emails/add.php:40 +msgid "Aggiungi Email per {0} \"{1}\"" +msgstr "Add Email for {0} \"{1}\"" + +#: ./templates/Emails/add.php:54 +#: ./templates/Emails/edit.php:54 +#: ./templates/Faxes/add.php:54 +#: ./templates/Faxes/edit.php:54 +#: ./templates/Groups/add.php:45 +#: ./templates/Groups/edit.php:50 +#: ./templates/Groups/handle_capabilities.php:71 +#: ./templates/MobilePhones/add.php:54 +#: ./templates/MobilePhones/edit.php:54 +#: ./templates/Organisations/add.php:172 +#: ./templates/Organisations/edit.php:86 +#: ./templates/Phones/add.php:53 +#: ./templates/Phones/edit.php:53 +#: ./templates/TelegramChats/add.php:53 +#: ./templates/TelegramChats/edit.php:53 +#: ./templates/Users/add.php:57 +#: ./templates/Users/choose_new_password.php:8 +#: ./templates/Users/edit.php:62 +msgid "Salva" +msgstr "Save" + +#: ./templates/Emails/edit.php:28 +msgid "Modifica Email" +msgstr "Edit Email" + +#: ./templates/Emails/edit.php:40 +msgid "Modifica Email per {0} \"{1}\"" +msgstr "Edit Email for {0} \"{1}\"" + +#: ./templates/Faxes/add.php:40 +msgid "Aggiungi Fax per {0} \"{1}\"" +msgstr "Add Fax for {0} \"{1}\"" + +#: ./templates/Faxes/edit.php:28 +msgid "Modifica Fax" +msgstr "Edit Fax" + +#: ./templates/Faxes/edit.php:40 +msgid "Modifica Fax per {0} \"{1}\"" +msgstr "Edit Fax for {0} \"{1}\"" + +#: ./templates/Groups/add.php:13 +#: ./templates/Groups/edit.php:13 +#: ./templates/Groups/handle_capabilities.php:13 +#: ./templates/Groups/index.php:13 +#: ./templates/Groups/index.php:24 +#: ./templates/Groups/view.php:13 +msgid "Lista dei Profili Utente" +msgstr "User Profiles List" + +#: ./templates/Groups/add.php:18 +#: ./templates/Groups/add.php:31 +msgid "Nuovo Profilo Utente" +msgstr "New User Profile" + +#: ./templates/Groups/edit.php:18 +#: ./templates/Groups/handle_capabilities.php:18 +#: ./templates/Groups/view.php:18 +msgid "Dettaglio Profilo Utente" +msgstr "User Profile Details" + +#: ./templates/Groups/edit.php:23 +#: ./templates/Groups/edit.php:36 +msgid "Modifica Profilo Utente" +msgstr "Edit User Profile" + +#: ./templates/Groups/handle_capabilities.php:35 +msgid "Competenze associate al Profilo Utente \"{0}\"" +msgstr "User Profile \"{0}\" associated capabilities" + +#: ./templates/Groups/handle_capabilities.php:45 +msgid "Gruppo di competenze non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability Groups not visible and not configurable by non SYSADMIN users" + +#: ./templates/Groups/handle_capabilities.php:52 +msgid "Gruppo di competenze \"{0}\"" +msgstr "Capability Group \"{0}\"" + +#: ./templates/Groups/index.php:44 +#: ./templates/Organisations/index.php:52 +#: ./templates/Users/index.php:48 +#: ./templates/plugin/AdminLTE/element/nav-top.php:118 +msgid "Dettaglio" +msgstr "Details" + +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +msgid "Sei sicuro che vuoi cancellare il profilo \"{0}\" ?" +msgstr "Are you sure you want to delete the user profile \"{0}\" ?" + +#: ./templates/Groups/view.php:30 +msgid "Informazioni Profilo Utente" +msgstr "User Profile Informations" + +#: ./templates/Maps/index.php:25 +msgid "Mappa" +msgstr "Map" + +#: ./templates/Maps/index.php:30 +msgid "Campo esistente appartenente al form ospite" +msgstr "Existing field that belongs to the hosting form" + +#: ./templates/Maps/index.php:37 +msgid "Posizione Evento" +msgstr "Incident location" + +#: ./templates/Maps/index.php:54 +msgid "Collezione di geometrie" +msgstr "Geometry collection" + +#: ./templates/Maps/index.php:65 +#: ./templates/Organisations/add.php:74 +msgid "Longitudine" +msgstr "Longitude" + +#: ./templates/Maps/index.php:76 +#: ./templates/Organisations/add.php:85 +msgid "Latitudine" +msgstr "Latitude" + +#: ./templates/Maps/index.php:87 +#: ./templates/Organisations/add.php:96 +#: ./templates/Organisations/add.php:158 +#: ./templates/Organisations/edit.php:62 +#: ./templates/Organisations/view.php:51 +msgid "Coordinate (Longitudine Latitudine)" +msgstr "Coordinates (Longitude Latitude)" + +#: ./templates/Maps/index.php:98 +#: ./templates/Organisations/add.php:107 +msgid "Cap" +msgstr "ZIP code" + +#: ./templates/Maps/index.php:142 +#: ./templates/Organisations/add.php:151 +msgid "Descrizione luogo" +msgstr "Location description" + +#: ./templates/MobilePhones/add.php:40 +msgid "Aggiungi Cellulare per {0} \"{1}\"" +msgstr "Add Mobile Phone for {0} \"{1}\"" + +#: ./templates/MobilePhones/edit.php:28 +msgid "Modifica Cellulare" +msgstr "Edit Mobile Phone" + +#: ./templates/MobilePhones/edit.php:40 +msgid "Modifica Cellulare per {0} \"{1}\"" +msgstr "Edit Mobile Phone for {0} \"{1}\"" + +#: ./templates/Organisations/add.php:13 +#: ./templates/Organisations/edit.php:13 +#: ./templates/Organisations/index.php:13 +#: ./templates/Organisations/view.php:13 +msgid "Lista Organizzazioni" +msgstr "Organisations List" + +#: ./templates/Organisations/add.php:18 +#: ./templates/Organisations/add.php:30 +msgid "Nuova Organizzazione" +msgstr "New Organisation" + +#: ./templates/Organisations/add.php:39 +#: ./templates/Organisations/edit.php:43 +#: ./templates/Organisations/view.php:38 +msgid "Tipo organizzazione" +msgstr "Organisation type" + +#: ./templates/Organisations/add.php:46 +#: ./templates/Organisations/edit.php:50 +#: ./templates/Organisations/view.php:45 +msgid "Posizione Organizzazione" +msgstr "Organisation Location" + +#: ./templates/Organisations/edit.php:18 +#: ./templates/Organisations/view.php:18 +#: ./templates/Organisations/view.php:29 +msgid "Dettaglio Organizzazione" +msgstr "Organisation Details" + +#: ./templates/Organisations/edit.php:23 +#: ./templates/Organisations/edit.php:34 +msgid "Modifica Organizzazione" +msgstr "Edit Organisation" + +#: ./templates/Organisations/index.php:23 +msgid "Lista delle {0} Organizzazioni" +msgstr "List of {0} Organisations" + +#: ./templates/Organisations/index.php:23 +#: ./templates/Users/index.php:23 +msgid "{0} su {1}" +msgstr "{0} out of {1}" + +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +msgid "Sei sicuro che vuoi cancellare l'organizzazione \"{0}\" ?" +msgstr "Are you sure you want to delete the organisation \"{0}\" ?" + +#: ./templates/Phones/add.php:40 +msgid "Aggiungi Telefono per {0} \"{1}\"" +msgstr "Add Phone for {0} \"{1}\"" + +#: ./templates/Phones/edit.php:28 +msgid "Modifica Telefono" +msgstr "Edit Phone" + +#: ./templates/Phones/edit.php:40 +msgid "Modifica Telefono per {0} \"{1}\"" +msgstr "Edit Phone for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:40 +msgid "Aggiungi Chat Telegram per {0} \"{1}\"" +msgstr "Add Telegram Chat for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:47 +#: ./templates/TelegramChats/edit.php:47 +msgid "Chat Telegram ID" +msgstr "Telegram Chat ID" + +#: ./templates/TelegramChats/edit.php:28 +msgid "Modifica Chat Telegram" +msgstr "Edit Telegram Chat" + +#: ./templates/TelegramChats/edit.php:40 +msgid "Modifica Chat Telegram per {0} \"{1}\"" +msgstr "Edit Telegram Chat for {0} \"{1}\"" + +#: ./templates/Users/add.php:13 +#: ./templates/Users/edit.php:13 +#: ./templates/Users/index.php:13 +#: ./templates/Users/view.php:13 +msgid "Lista Utenti" +msgstr "Users List" + +#: ./templates/Users/add.php:18 +#: ./templates/Users/add.php:31 +msgid "Nuovo Utente" +msgstr "New User" + +#: ./templates/Users/add.php:38 +#: ./templates/Users/edit.php:43 +#: ./templates/Users/view.php:41 +msgid "Nome utente" +msgstr "Username" + +#: ./templates/Users/add.php:39 +#: ./templates/Users/edit.php:44 +msgid "Password" +msgstr "Password" + +#: ./templates/Users/add.php:42 +#: ./templates/Users/edit.php:47 +#: ./templates/Users/view.php:47 +msgid "Codice Fiscale" +msgstr "Tax ID code" + +#: ./templates/Users/add.php:43 +#: ./templates/Users/edit.php:48 +#: ./templates/Users/view.php:49 +msgid "Data di nascita" +msgstr "Date of birth" + +#: ./templates/Users/add.php:44 +#: ./templates/Users/edit.php:49 +#: ./templates/Users/view.php:51 +msgid "Luogo di nascita" +msgstr "Birth place" + +#: ./templates/Users/add.php:45 +#: ./templates/Users/edit.php:50 +#: ./templates/Users/view.php:53 +msgid "Sesso" +msgstr "Gender" + +#: ./templates/Users/add.php:47 +#: ./templates/Users/edit.php:52 +#: ./templates/Users/view.php:57 +msgid "Città" +msgstr "City" + +#: ./templates/Users/add.php:49 +#: ./templates/Users/edit.php:54 +#: ./templates/Users/view.php:61 +msgid "Lingua preferita" +msgstr "Favourite language" + +#: ./templates/Users/add.php:51 +#: ./templates/Users/edit.php:56 +msgid "Foto del profilo (solo jpeg di dimensioni 160x160!)" +msgstr "Photo (160x160 sized jpeg only!)" + +#: ./templates/Users/choose_new_password.php:4 +msgid "Imposta una nuova password" +msgstr "Set a new password" + +#: ./templates/Users/choose_new_password.php:5 +msgid "Digita la nuova password" +msgstr "Enter the new password" + +#: ./templates/Users/choose_new_password.php:6 +msgid "Ridigita la nuova password" +msgstr "Retype the previous entered password" + +#: ./templates/Users/edit.php:18 +#: ./templates/Users/view.php:18 +msgid "Dettaglio Utente" +msgstr "User Details" + +#: ./templates/Users/edit.php:23 +#: ./templates/Users/edit.php:36 +msgid "Modifica Utente" +msgstr "Edit User" + +#: ./templates/Users/index.php:23 +msgid "Lista dei {0} Utenti" +msgstr "List of {0} Users" + +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Sei sicuro che vuoi cancellare l'utente \"{0}\" ?" +msgstr "Are you sure you wanto to delete the user \"{0}\" ?" + +#: ./templates/Users/login.php:4 +msgid "Accedi" +msgstr "Gain access" + +#: ./templates/Users/login.php:8 +msgid "Login" +msgstr "Login" + +#: ./templates/Users/password_recovery.php:4 +msgid "Inserisci un indirizzo email associato alla tua utenza" +msgstr "Insert an email that is currently associated with your account" + +#: ./templates/Users/password_recovery.php:7 +msgid "Richiedi reset password" +msgstr "Request password reset" + +#: ./templates/Users/view.php:30 +msgid "Informazioni Utente" +msgstr "User Informations" + +#: ./templates/Users/view.php:34 +msgid "Elimina foto" +msgstr "Delete photo" + +#: ./templates/Users/view.php:34 +msgid "Sei sicuro che vuoi eliminare la foto ?" +msgstr "Are you sure you want to delete the photo ?" + +#: ./templates/Users/view.php:62 +msgid "Non specificata" +msgstr "Not specified" + +#: ./templates/Users/view.php:67 +msgid "Recapiti:" +msgstr "Contacts" + +#: ./templates/cell/FilterInput/display.php:9 +#: ./templates/element/attachments.php:127 +msgid "Rimuovi" +msgstr "Remove" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:113 +msgid "Filtri attivi" +msgstr "Filters applied" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:116 +msgid "Filtri disattivati" +msgstr "No Filters applied" + +#: ./templates/cell/Filters/display.php:15 +msgid "Aggiungi un filtro" +msgstr "Add a filter" + +#: ./templates/cell/Filters/display.php:34 +#: ./templates/cell/Filters/display.php:55 +msgid "Applica" +msgstr "Apply" + +#: ./templates/cell/Filters/display.php:39 +msgid "Reset" +msgstr "Reset" + +#: ./templates/cell/Filters/display.php:56 +msgid "Annulla" +msgstr "Cancel" + +#: ./templates/cell/Filters/display.php:58 +msgid "A" +msgstr "TO" + +#: ./templates/cell/Filters/display.php:59 +msgid "Dal Al" +msgstr "From To" + +#: ./templates/cell/Filters/display.php:60 +#: ./templates/cell/Filters/display.php:87 +msgid "Oggi" +msgstr "Today" + +#: ./templates/cell/Filters/display.php:62 +msgid "Dom" +msgstr "Sun" + +#: ./templates/cell/Filters/display.php:63 +msgid "Lun" +msgstr "Mon" + +#: ./templates/cell/Filters/display.php:64 +msgid "Mar" +msgstr "Tue" + +#: ./templates/cell/Filters/display.php:65 +msgid "Mer" +msgstr "Wed" + +#: ./templates/cell/Filters/display.php:66 +msgid "Gio" +msgstr "Thu" + +#: ./templates/cell/Filters/display.php:67 +msgid "Ven" +msgstr "Fri" + +#: ./templates/cell/Filters/display.php:68 +msgid "Sab" +msgstr "Sat" + +#: ./templates/cell/Filters/display.php:71 +msgid "Gennaio" +msgstr "January" + +#: ./templates/cell/Filters/display.php:72 +msgid "Febbraio" +msgstr "February" + +#: ./templates/cell/Filters/display.php:73 +msgid "Marzo" +msgstr "March" + +#: ./templates/cell/Filters/display.php:74 +msgid "Aprile" +msgstr "April" + +#: ./templates/cell/Filters/display.php:75 +msgid "Maggio" +msgstr "May" + +#: ./templates/cell/Filters/display.php:76 +msgid "Giugno" +msgstr "June" + +#: ./templates/cell/Filters/display.php:77 +msgid "Luglio" +msgstr "July" + +#: ./templates/cell/Filters/display.php:78 +msgid "Agosto" +msgstr "August" + +#: ./templates/cell/Filters/display.php:79 +msgid "Settembre" +msgstr "September" + +#: ./templates/cell/Filters/display.php:80 +msgid "Ottobre" +msgstr "October" + +#: ./templates/cell/Filters/display.php:81 +msgid "Novembre" +msgstr "November" + +#: ./templates/cell/Filters/display.php:82 +msgid "Dicembre" +msgstr "December" + +#: ./templates/cell/Filters/display.php:88 +msgid "Ieri" +msgstr "Yesterday" + +#: ./templates/cell/Filters/display.php:89 +msgid "Questa settimana" +msgstr "This week" + +#: ./templates/cell/Filters/display.php:90 +msgid "Questo mese" +msgstr "This month" + +#: ./templates/cell/Filters/display.php:91 +msgid "Lo scorso mese" +msgstr "Last month" + +#: ./templates/cell/Filters/display.php:92 +msgid "Ultimi 7 giorni" +msgstr "Last 7 days" + +#: ./templates/cell/Filters/display.php:93 +msgid "Ultimi 15 giorni" +msgstr "Last 15 days" + +#: ./templates/cell/Filters/display.php:94 +msgid "Ultimi 30 giorni" +msgstr "Last 30 days" + +#: ./templates/cell/Filters/display.php:131 +msgid "Errore durante il recupero del filtro selezionato. Riprovare di nuovo" +msgstr "Error trying to retrieve the selected filter. Pleas try again" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:118 +#: ./templates/element/Map.php:122 +msgid "OpenStreetMap ONLINE" +msgstr "OpenStreetMap ONLINE" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:127 +#: ./templates/element/Map.php:131 +msgid "OpenStreetMap OFFLINE" +msgstr "OpenStreetMap OFFLINE" + +#: ./templates/element/Map.php:312 +#: ./templates/element/Map.php:541 +msgid "Indirizzo non trovato o fuori dall'area di competenza" +msgstr "Address not found or out of the platform configured bounding box" + +#: ./templates/element/Map.php:530 +msgid "Punto alle coordinate (EPSG:4326) Latitudine:" +msgstr "Point of coordinates (EPSG:4326) Latitude:" + +#: ./templates/element/Map.php:530 +msgid "Longitudine:" +msgstr "Longitude:" + +#: ./templates/element/MapCore/MapPrimitives.php:10 +msgid "Scegli un risultato:" +msgstr "Pick a result" + +#: ./templates/element/MapCore/MapPrimitives.php:30 +msgid "Inserisci un indirizzo o le coordinate (in formato EPSG:4326)" +msgstr "Insert an address or coordinates (EPSG:4326)" + +#: ./templates/element/MapCore/MapPrimitives.php:31 +msgid "Cerca un indirizzo" +msgstr "Look up for an address" + +#: ./templates/element/MapCore/MapPrimitives.php:36 +msgid "Inserisci un punto in mappa" +msgstr "Insert a point on map" + +#: ./templates/element/MapCore/MapPrimitives.php:41 +msgid "Inserisci un poligono in mappa" +msgstr "Draw a polygon on map" + +#: ./templates/element/MapCore/MapPrimitives.php:46 +msgid "Inserisci un cerchio in mappa" +msgstr "Draw a circle on map" + +#: ./templates/element/MapCore/MapPrimitives.php:51 +msgid "Cancella una geometria" +msgstr "Delete a geometry" + +#: ./templates/element/attachmentPreview.php:16 +msgid "Il tuo browser non supporta HTML5 video tag. Prova ad aggiornare il tuo browser." +msgstr "Your browser doesn't seem to support HTML5 video tag. Please try and update your browser to a more recent version." + +#: ./templates/element/attachmentPreview.php:35 +msgid "Anteprima non disponibile" +msgstr "Preview not available" + +#: ./templates/element/attachments.php:30 +msgid "di tipo: \"{0}\"" +msgstr "of type \"{0}\"" + +#: ./templates/element/attachments.php:39 +msgid "Mostra allegati correlati" +msgstr "Show also linked attachments" + +#: ./templates/element/attachments.php:48 +msgid "Allega un file " +msgstr "Attach a file" + +#: ./templates/element/attachments.php:48 +msgid "Allega files " +msgstr "Attach files" + +#: ./templates/element/attachments.php:54 +msgid "Allega file pubblico " +msgstr "Attach public file" + +#: ./templates/element/attachments.php:54 +msgid "Allega un file privato " +msgstr "Attach a private file" + +#: ./templates/element/attachments.php:54 +msgid "Allega files privati " +msgstr "Attach private files " + +#: ./templates/element/attachments.php:58 +msgid "Allega files..." +msgstr "Attach files..." + +#: ./templates/element/attachments.php:65 +msgid "Allega files {1} {0}" +msgstr "Attach files {1} {0}" + +#: ./templates/element/attachments.php:118 +msgid "latitudine" +msgstr "latitude" + +#: ./templates/element/attachments.php:119 +msgid "longitudine" +msgstr "longitude" + +#: ./templates/layout/error.php:38 +msgid "Back" +msgstr "Back" + +#: ./templates/plugin/AdminLTE/element/aside-control-sidebar.php:4 +msgid "Notifiche" +msgstr "Notifications" + +#: ./templates/plugin/AdminLTE/element/footer.php:6 +msgid "Versione" +msgstr "Version" + +#: ./templates/plugin/AdminLTE/element/footer.php:9 +msgid "Tutti i diritti riservati" +msgstr "All rights reserved" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:67 +msgid "Nuove notifiche: {0}" +msgstr "New notifications: {0}" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:91 +msgid "Segna tutte le notifiche come lette" +msgstr "Mark all new notifications as read" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:121 +msgid "Esci" +msgstr "Logout" + diff --git a/idrocap_wa/resources/locales/it/cake.po b/idrocap_wa/resources/locales/it/cake.po new file mode 100644 index 0000000..799b01c --- /dev/null +++ b/idrocap_wa/resources/locales/it/cake.po @@ -0,0 +1,279 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: CakePHP 4.4.5\n" +"POT-Creation-Date: 2023-02-28 09:27+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./templates/Error/error400.php:39 +#: ./templates/Error/error500.php:43 +msgid "Error" +msgstr "Errore" + +#: ./templates/Error/error400.php:40 +msgid "The requested address {0} was not found on this server." +msgstr "L'indirizzo richiesto {0} non è stato trovato su questo server." + +#: ./templates/Error/error500.php:41 +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:361 +msgid "An Internal Error Has Occurred." +msgstr "Errore interno." + +#: ./vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php:462 +msgid "You are not authorized to access that location." +msgstr "Non sei autorizzato ad accedere a quella risorsa." + +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:359 +msgid "Not Found" +msgstr "Non Trovato" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:390 +msgid "Missing or incorrect CSRF cookie type." +msgstr "tipo di CSRF cookie mancante o incorretto." + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:394 +msgid "Missing or invalid CSRF cookie." +msgstr "CSRF cookie mancante o incorretto." + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:417 +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:265 +msgid "CSRF token from either the request body or request headers did not match or is missing." +msgstr "Il CSRF token è mancante o quello presente nel body non corrisponde." + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:247 +msgid "Missing or incorrect CSRF session key" +msgstr "Chiave di sessione CSRF incorretta o mancante" + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1489 +msgid "The requested file contains `..` and will not be read." +msgstr "Il file richiesto contiene `..` e quindi non verrà letto." + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1497 +msgid "The requested file was not found" +msgstr "Il file richiesto non è stato trovato" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:116 +msgid "{0,number,#,###.##} KB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:118 +msgid "{0,number,#,###.##} MB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:120 +msgid "{0,number,#,###.##} GB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:122 +msgid "{0,number,#,###.##} TB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:114 +msgid "{0,number,integer} Byte" +msgid_plural "{0,number,integer} Bytes" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} from now" +msgstr "{0} da adesso" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} ago" +msgstr "{0} fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} after" +msgstr "{0} dopo" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} before" +msgstr "{0} prima" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:120 +msgid "just now" +msgstr "in questo momento" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:157 +msgid "about a second ago" +msgstr "circa un secondo fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:158 +msgid "about a minute ago" +msgstr "circa un minuto fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:159 +msgid "about an hour ago" +msgstr "circa un'ora fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:160 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:370 +msgid "about a day ago" +msgstr "circa un giorno fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:161 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:371 +msgid "about a week ago" +msgstr "circa una settimana fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:162 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:372 +msgid "about a month ago" +msgstr "circa un mese fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:163 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:373 +msgid "about a year ago" +msgstr "circa un anno fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:174 +msgid "in about a second" +msgstr "fra circa un secondo" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:175 +msgid "in about a minute" +msgstr "fra circa un minuto" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:176 +msgid "in about an hour" +msgstr "fra circa un'ora" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:177 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:384 +msgid "in about a day" +msgstr "fra circa un giorno" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:178 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:385 +msgid "in about a week" +msgstr "tra circa una settimana" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:179 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:386 +msgid "in about a month" +msgstr "tra circa un mese" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:180 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:387 +msgid "in about a year" +msgstr "tra circa un anno" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:342 +msgid "today" +msgstr "oggi" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:409 +msgid "%s ago" +msgstr "%s fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:410 +msgid "on %s" +msgstr "%s" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:53 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:132 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:354 +msgid "{0} year" +msgid_plural "{0} years" +msgstr[0] "{0} anno" +msgstr[1] "{0} anni" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:57 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:135 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:357 +msgid "{0} month" +msgid_plural "{0} months" +msgstr[0] "{0} mese" +msgstr[1] "{0} mesi" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:63 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:138 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:360 +msgid "{0} week" +msgid_plural "{0} weeks" +msgstr[0] "{0} settimana" +msgstr[1] "{0} settimane" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:65 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:141 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:363 +msgid "{0} day" +msgid_plural "{0} days" +msgstr[0] "{0} giorno" +msgstr[1] "{0} giorni" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:70 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:144 +msgid "{0} hour" +msgid_plural "{0} hours" +msgstr[0] "{0} ora" +msgstr[1] "{0} ore" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:74 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:147 +msgid "{0} minute" +msgid_plural "{0} minutes" +msgstr[0] "{0} minuto" +msgstr[1] "{0} minuti" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:78 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:150 +msgid "{0} second" +msgid_plural "{0} seconds" +msgstr[0] "{0} secondo" +msgstr[1] "{0} secondi" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:63 +msgid "This value is already in use" +msgstr "Questo valore è già in uso" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:110 +msgid "This value does not exist" +msgstr "Questo valore non esiste" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:232 +msgid "Cannot modify row: a constraint for the `{0}` association fails." +msgstr "Impossibile modificare: il vincolo per l'associazione `{0}` fallisce." + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:270 +msgid "The count does not match {0}{1}" +msgstr "Il conteggio non corrisponde {0}{1}" + +#: ./vendor/cakephp/cakephp/src/Utility/Text.php:923 +msgid "and" +msgstr "e" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2539 +msgid "This field is required" +msgstr "Questo campo è richiesto" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2559 +#: ./vendor/cakephp/cakephp/src/View/Form/ArrayContext.php:249 +msgid "This field cannot be left empty" +msgstr "Questo campo non può essere lasciato vuoto" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2711 +msgid "The provided value is invalid" +msgstr "Il valore fornito non è valido" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:979 +msgid "Edit {0}" +msgstr "Modifica {0}" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:981 +msgid "New {0}" +msgstr "Nuovo {0}" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:1917 +msgid "Submit" +msgstr "Salva" + diff --git a/idrocap_wa/src/Application.php b/idrocap_wa/src/Application.php new file mode 100644 index 0000000..6cdeb82 --- /dev/null +++ b/idrocap_wa/src/Application.php @@ -0,0 +1,268 @@ +addPlugin('Authentication'); + + if (PHP_SAPI === 'cli') { + $this->bootstrapCli(); + } else { + FactoryLocator::add( + 'Table', + (new TableLocator())->allowFallbackClass(false) + ); + } + + /* + * Only try to load DebugKit in development mode + * Debug Kit should not be installed on a production system + */ + if (Configure::read('debug')) { + Configure::write('DebugKit.safeTld', ['it']); + } + + // Load more plugins here + $this->addPlugin('Muffin/Trash'); + $this->addPlugin('CsvView'); + $this->addPlugin('CakeSentry'); + } + + + /** + * Returns a service provider instance. + * + * @param \Psr\Http\Message\ServerRequestInterface $request Request + * @return \Authentication\AuthenticationServiceInterface + */ + public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface + { + $service = new AuthenticationService(); + + $fields = [ + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password' + ]; + + if (strpos($request->getPath(), '/api/') !== 0) { + // NORMAL REQUESTS + + // se si tratta della request "/notifications/index" non eseguire il redirect e restituisci 401! + if ($request->getPath() !== '/notifications/index') { + // Define where users should be redirected to when they are not authenticated + $service->setConfig([ + 'unauthenticatedRedirect' => Router::url([ + 'prefix' => false, + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + 'queryParam' => 'redirect', + ]); + } + + // Load the authenticators. Session should be first. + $service->loadAuthenticator('Authentication.Session'); + + $service->loadAuthenticator('Authentication.Cookie', [ + 'fields' => $fields, + 'loginUrl' => Router::url([ + 'prefix' => false, + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + ]); + + $service->loadAuthenticator('Authentication.Form', [ + 'fields' => $fields, + 'loginUrl' => Router::url([ + 'prefix' => false, + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + ]); + + // Load identifiers + $service->loadIdentifier('JixelPassword', [ + 'fields' => $fields, + ]); + } else { + // API REQUESTS + + if (strpos($request->getPath(), '/api/users/login') === 0) { + // API REQUEST LOGIN + + // Load the authenticators. + $service->loadAuthenticator('Authentication.Form', [ + 'fields' => $fields, + 'loginUrl' => Router::url([ + 'prefix' => 'Api', + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + ]); + + // Load identifiers + $service->loadIdentifier('Authentication.Password', compact('fields')); + } else { + // Load identifiers + $service->loadIdentifier('Authentication.JwtSubject', [ + 'tokenField' => 'username', + ]); + + // Load the authenticators + $service->loadAuthenticator('Authentication.Jwt', [ + 'secretKey' => file_get_contents(Configure::read('App.jwt.keys.public')), + 'algorithm' => Configure::read('App.jwt.algorithm'), + 'returnPayload' => false + ]); + } + } + return $service; + } + + /** + * Setup the middleware queue your application will use. + * + * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup. + * @return \Cake\Http\MiddlewareQueue The updated middleware queue. + */ + public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue + { + $middlewareQueue + ->add(new LocaleSelectorMiddleware(['it', 'en'])) + + // Catch any exceptions in the lower layers, + // and make an error page/response + ->add(new ErrorHandlerMiddleware(Configure::read('Error'))) + + // Handle plugin/theme assets like CakePHP normally does. + ->add(new AssetMiddleware([ + 'cacheTime' => Configure::read('Asset.cacheTime'), + ])) + + // Add routing middleware. + // If you have a large number of routes connected, turning on routes + // caching in production could improve performance. For that when + // creating the middleware instance specify the cache config name by + // using it's second constructor argument: + // `new RoutingMiddleware($this, '_cake_routes_')` + ->add(new RoutingMiddleware($this)) + + // Parse various types of encoded request bodies so that they are + // available as array through $request->getData() + // https://book.cakephp.org/4/en/controllers/middleware.html#body-parser-middleware + ->add(new BodyParserMiddleware()); + + // Cross Site Request Forgery (CSRF) Protection Middleware + // https://book.cakephp.org/4/en/security/csrf.html#cross-site-request-forgery-csrf-middleware + $csrf = new CsrfProtectionMiddleware(); + + // Token check will be skipped when callback returns `true`. + $csrf->skipCheckCallback(function ($request) { + // Skip token check for API URLs. + if ($request->getParam('prefix') === 'Api') { + return true; + } + // Skip token check for ajax calls. + if ($request->is('ajax')) { + return true; + } + }); + + // Ensure routing middleware is added to the queue before CSRF protection middleware. + $middlewareQueue->add($csrf) + // encryption/decryption management of listed cookies: + ->add(new EncryptedCookieMiddleware(['CookieAuth'], Configure::read('Security.CookieEncryptionKey'))) + + // Add the AuthenticationMiddleware. It should be + // after routing and body parser. + ->add(new AuthenticationMiddleware($this)) + ->add(new UserTimezoneDatetimeRequestDataMiddleware()); + + return $middlewareQueue; + } + + /** + * Register application container services. + * + * @param \Cake\Core\ContainerInterface $container The Container to update. + * @return void + * @link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection + */ + public function services(ContainerInterface $container): void + { + } + + /** + * Bootstrapping for CLI application. + * + * That is when running commands. + * + * @return void + */ + protected function bootstrapCli(): void + { + $this->addOptionalPlugin('Cake/Repl'); + + // Load more plugins here + } +} diff --git a/idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php b/idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php new file mode 100644 index 0000000..3893135 --- /dev/null +++ b/idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php @@ -0,0 +1,95 @@ +addArgument('chunk_size', [ + 'help' => 'the amount of records to process in chunk (at least 10 which is the default value)', + 'required' => false, + ]); + return $parser; + } + + /* + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $chunkSize = (int)($args->getArgument('chunk_size') ?? 10); + if ($chunkSize < 10) $io->abort("Please specify a chunk size of at least 10!"); + $page = 1; + $total = 0; + $io->info("AddCadastralCodeToUsesCommand started!"); + $io->info("Chunk size is: $chunkSize"); + + do { + $intendedUses = $this->fetchTable('WaterDrawingIntendedUses')->find() + ->where([ + // recuperiamo solo le entries di tipo uso IRRIGUO che non hanno il codice BELFIORE: + "WaterDrawingIntendedUses.water_drawing_intended_use_type_id" => 1, + "WaterDrawingIntendedUses.cadastral_code IS NULL", + + // devono però avere foglio e particella validi: + "WaterDrawingIntendedUses.cadastral_sheet IS NOT NULL", + "WaterDrawingIntendedUses.cadastral_parcel IS NOT NULL", + "WaterDrawingIntendedUses.cadastral_sheet <> ''", + "WaterDrawingIntendedUses.cadastral_parcel <> ''", + ]) + ->limit($chunkSize) + ->page($page) + ->all(); + + foreach($intendedUses as $intendedUse){ + $io->info("Processing WaterDrawingIntendedUse with ID: $intendedUse->id"); + // recuperiamo il codice BELFIORE dal primo delle derivazioni connesse alla pratica (se ve ne sono....): + $derivation = $this->fetchTable('WaterDrawingDerivations')->find()->where([ + 'WaterDrawingDerivations.water_drawing_paperwork_id' => $intendedUse->water_drawing_paperwork_id + ])->first(); + if (!isset($derivation->cadastral_code)) { + $io->warning('WARNING: related water_drawing_paperwork has no suitable water_drawing_derivations to get cadastral_code from -> SKIPPED!'); + continue; + } + $intendedUse->cadastral_code = $derivation->cadastral_code; + $intendedUse->vegetation_match_status = CadastralUtils::isParcelWithinVegetationArea(strtolower($intendedUse->cadastral_code), $intendedUse->cadastral_sheet, $intendedUse->cadastral_parcel) ? 1 : -1; + + if(!$this->fetchTable('WaterDrawingIntendedUses')->save($intendedUse, ['skipResetIsMismatch' => true])){ + $io->warning('WARNING: Error during save!'); + $io->warning(json_encode($intendedUse->getErrors())); + } + } + + $count = $intendedUses->count(); + $total += $count; + if ($count) $io->success("processed $count items for page $page"); + $page++; + } while ($count === $chunkSize); + + $io->success("total processed $total items!"); + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php b/idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php new file mode 100644 index 0000000..5695e31 --- /dev/null +++ b/idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php @@ -0,0 +1,44 @@ +fetchTable('WaterDrawingDerivations')->find()->where([ + 'WaterDrawingDerivations.latitude' => '', + 'WaterDrawingDerivations.longitude' => '', + 'WaterDrawingDerivations.cadastral_code IS NOT NULL', + 'WaterDrawingDerivations.cadastral_sheet IS NOT NULL', + 'WaterDrawingDerivations.cadastral_parcel IS NOT NULL', + ])->toArray(); + foreach($derivations as $derivation){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($derivation->cadastral_code), (string) $derivation->cadastral_sheet, (string) $derivation->cadastral_parcel); + if(isset($coordinates)){ + $derivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($derivation, [ + 'latitude' => $coordinates->latitude, + 'longitude' => $coordinates->longitude, + 'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":['. $coordinates->longitude .','. $coordinates->latitude .']},"properties":null}]}' + ]); + if(!$this->fetchTable('WaterDrawingDerivations')->save($derivation)){ + $io->out(__('Errore durante il salvataggio.')); + $io->out(json_encode($derivation->getErrors())); + } + } + } + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php b/idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php new file mode 100644 index 0000000..44a04b0 --- /dev/null +++ b/idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php @@ -0,0 +1,57 @@ +info("\n\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: START!!!"); + + // prima recupero, per ogni pratica, le water_drawing_antimafia_certification_requests con ID massimo + // questo mi assicura di prendere in considerazione l'ultima richiesta fatta: + $latest_water_drawing_antimafia_certification_request_ids = $this->fetchTable('WaterDrawingAntimafiaCertificationRequests') + ->find() + ->select(['max_id' => 'MAX(WaterDrawingAntimafiaCertificationRequests.id)']) + ->group('water_drawing_paperwork_id'); + + // quindi recuoero le pratiche per cui risulti l'ultima richiesta AM scaduta (termine dei 30gg) + // che sia in "stato richiesta" in modo da poter notificare i relativi utenti DRAR: + $to_be_notified_water_drawing_paperworks = $this->fetchTable('WaterDrawingPaperworks') + ->find() + ->matching('WaterDrawingAntimafiaCertificationRequests') + ->where([ + 'WaterDrawingAntimafiaCertificationRequests.id IN' => $latest_water_drawing_antimafia_certification_request_ids, + 'WaterDrawingAntimafiaCertificationRequests.water_drawing_antimafia_certification_request_status_id' => 2, + 'WaterDrawingAntimafiaCertificationRequests.created <= NOW() - INTERVAL 30 DAY' + ]) + ->toArray(); + + foreach($to_be_notified_water_drawing_paperworks as $waterDrawingPaperwork) { + // DISPATCH NOTIFICHE: + $io->info("\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: richiesta AM scaduta per pratica con ID: " . $waterDrawingPaperwork->id); + if (isset($waterDrawingPaperwork->drar_user_id)) { + $io->success("CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: Invio notifica a utente DRAR con ID: " . $waterDrawingPaperwork->drar_user_id); + // invio notifica a utente DRAR che aveva richiesto la certificazione antimafia perchè la richiesta è scaduta: + NotificationsHandler::dispatch($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user_antimafia_request_expired', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + $io->error("CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: LA PRATICA NON HA UTENTI DRAR ASSEGNATI !!!!!"); + } + } + + $io->info("\n\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: END!!!"); + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/CopyTranslationsCommand.php b/idrocap_wa/src/Command/CopyTranslationsCommand.php new file mode 100644 index 0000000..8363d6e --- /dev/null +++ b/idrocap_wa/src/Command/CopyTranslationsCommand.php @@ -0,0 +1,144 @@ +addArgument('template_filename', [ + 'help' => '.POT Template file (with full or relative path)', + 'required' => true, + ]) + ->addArgument('input_filename', [ + 'help' => '.PO Input file (with full or relative path)', + 'required' => true, + ]) + ->addArgument('output_filename', [ + 'help' => 'Output PO file (with full or relative path)', + 'required' => true, + ]); + return $parser; + } + + /** + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $template_filename = $args->getArgument('template_filename'); + $input_filename = $args->getArgument('input_filename'); + $output_filename = $args->getArgument('output_filename'); + + $io->info("\n\ntemplate file path: $template_filename, input file path: $input_filename, output file path: $output_filename\n\n"); + + if (!file_exists($template_filename)) $io->abort("\n\n\nError: File \"$template_filename\" doesn't exists!"); + if (!file_exists($input_filename)) $io->abort("\n\n\nError: File \"$input_filename\" doesn't exists!"); + + // lettura pot e retrieving identifiers: + $template_filename_handle = fopen($template_filename, "r"); + if ($template_filename_handle) { + $pot_row_count = 0; + $io->info("\n\n\nFetching translation identifiers from template file \"$template_filename\":\n"); + while (($buffer = fgets($template_filename_handle, 4096)) !== false) { + if (substr($buffer, 0, 5) !== "msgid") continue; + $text = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; + if ($text === "") continue; + ++$pot_row_count; + $io->info("msgid at row $pot_row_count: $text"); + $this->pot_identifiers[$text] = ""; + } + if (!feof($template_filename_handle)) { + $io->abort("\n\n\nError: unexpected fgets() fail"); + } + fclose($template_filename_handle); + $io->success("\n\nNumber of identifiers successfully fetched from template file \"$template_filename\": $pot_row_count\n\n"); + } else { + $io->abort("\n\n\nError: Unable to Open File \"$template_filename\"!"); + } + + // lettura input file e retrieving translations (x gli identifiers che matchano): + $input_filename_handle = fopen($input_filename, "r"); + if ($input_filename_handle) { + $count = 0; + $last_identifier = null; + $io->info("\n\n\nRetrieving translations from input file \"$input_filename\":\n"); + while (($buffer = fgets($input_filename_handle, 4096)) !== false) { + if (substr($buffer, 0, 6) === "msgid ") { + $last_identifier = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; + if ($last_identifier === "" || !isset($this->pot_identifiers[$last_identifier])) $last_identifier = null; + } + if (substr($buffer, 0, 6) === "msgstr" && isset($last_identifier)) { + $this->pot_identifiers[$last_identifier] = explode("\"\n", explode("msgstr \"", $buffer)[1])[0]; + if (!empty($this->pot_identifiers[$last_identifier])) ++$count; + $io->info("Retrieved translations so far: $count - Parsing: \"$last_identifier\" = \"" . $this->pot_identifiers[$last_identifier] . "\""); + } + } + if (!feof($input_filename_handle)) { + $io->abort("\n\n\nError: unexpected fgets() fail"); + } + fclose($input_filename_handle); + $io->success("\n\nSuccessfully retrieved $count translations from input po file \"$input_filename\"!\n\n"); + } else { + $io->abort("\n\n\nError: Unable to Open File \"$input_filename\"!"); + } + + // creazione file .PO di output partendo da struttura del .POT fornito e arricchito con le traduzioni recuperate dal file di input + $template_filename_handle = fopen($template_filename, "r"); + $output_filename_handle = fopen($output_filename, 'w'); + + if ($template_filename_handle) { + $count = 0; + $last_identifier = null; + $io->info("\n\n\nCreating new translation file \"$output_filename\":\n"); + while (($buffer = fgets($template_filename_handle, 4096)) !== false) { + if (substr($buffer, 0, 5) === "msgid") { + $last_identifier = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; + if ($last_identifier !== "" && !empty($this->pot_identifiers[$last_identifier])) { + ++$count; + } else { + $last_identifier = null; + } + } + if (substr($buffer, 0, 6) === "msgstr" && isset($last_identifier)) { + $io->info("Adding translation number: $count for identifier: \"$last_identifier\"" . " with translation: \"" . $this->pot_identifiers[$last_identifier] . "\""); + $buffer = "msgstr \"" . $this->pot_identifiers[$last_identifier] . "\"\n"; + } + fwrite($output_filename_handle, $buffer); + } + if (!feof($template_filename_handle)) { + $io->abort("\n\n\nError: unexpected fgets() fail"); + } + fclose($template_filename_handle); + fclose($output_filename_handle); + $io->success("\n\nSuccessfully created po file \"$output_filename\" with $count added translations!\n\n"); + } else { + $io->abort("\n\n\nError: Unable to Open File \"$template_filename\"!"); + } + } +} diff --git a/idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php b/idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php new file mode 100644 index 0000000..6b26b14 --- /dev/null +++ b/idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php @@ -0,0 +1,107 @@ +addArgument('data', [ + 'help' => 'the serialized data to process', + 'required' => true, + ]); + return $parser; + } + + /* + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $io->info("IntendedUseVegetationCheckCommand - JOB STARTED!"); + $data = $args->getArgument('data'); + $io->info("IntendedUseVegetationCheckCommand - received data: {$data}"); + + $deserialized_data = json_decode($data, true); + + if (empty($deserialized_data['water_drawing_paperwork_id'])) { + $io->abort("IntendedUseVegetationCheckCommand - water_drawing_paperwork_id is missing!"); + } + + $water_drawing_paperwork = $this->fetchTable('WaterDrawingPaperworks')->find()->where(['WaterDrawingPaperworks.id' => $deserialized_data['water_drawing_paperwork_id']])->first(); + if (!$water_drawing_paperwork) { + $io->abort("IntendedUseVegetationCheckCommand - water_drawing_paperwork with ID: {$deserialized_data['water_drawing_paperwork_id']} not found!"); + } + + $water_drawing_intended_uses = $this->fetchTable('WaterDrawingIntendedUses')->find()->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $water_drawing_paperwork->id])->all(); + + $intended_use_linked = count($water_drawing_intended_uses); + $intended_use_processed = 0; + + foreach ($water_drawing_intended_uses as $water_drawing_intended_use) { + $io->info("IntendedUseVegetationCheckCommand - checking linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id}, cadastral_code: {$water_drawing_intended_use->cadastral_code}, cadastral_sheet: {$water_drawing_intended_use->cadastral_sheet}, cadastral_parcel: {$water_drawing_intended_use->cadastral_parcel}, water_drawing_intended_use_type_id: {$water_drawing_intended_use->water_drawing_intended_use_type_id}..."); + if ($water_drawing_intended_use->water_drawing_intended_use_type_id != 1) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has water_drawing_intended_use_type_id: {$water_drawing_intended_use->water_drawing_intended_use_type_id} (must be 1), SKIPPED!"); + continue; + } + if (empty($water_drawing_intended_use->cadastral_code)) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_code, SKIPPED!"); + continue; + } + if (empty($water_drawing_intended_use->cadastral_sheet)) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_sheet, SKIPPED!"); + continue; + } + if (empty($water_drawing_intended_use->cadastral_parcel)) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_parcel, SKIPPED!"); + continue; + } + $water_drawing_intended_use->vegetation_match_status = CadastralUtils::isParcelWithinVegetationArea(strtolower($water_drawing_intended_use->cadastral_code), $water_drawing_intended_use->cadastral_sheet, $water_drawing_intended_use->cadastral_parcel) ? 1 : -1; + if ($water_drawing_intended_use->vegetation_match_status == -1) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO MATCHING INTENDED USE!!!"); + } else { + $io->success("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has PERFECT MATCHING INTENDED USE!"); + } + if (!$this->fetchTable('WaterDrawingIntendedUses')->save($water_drawing_intended_use, ['skipResetIsMismatch' => true])) { + $io->error("IntendedUseVegetationCheckCommand - error saving processed water_drawing_intended_use with ID: {$water_drawing_intended_use->id}"); + } else { + $intended_use_processed++; + } + } + + $io->success("IntendedUseVegetationCheckCommand - checked {$intended_use_linked} linked intended uses and successfully processed {$intended_use_processed} of them!"); + + if (!empty($deserialized_data['notification_user_id'])) { + $user_to_be_notified_id = $deserialized_data['notification_user_id']; + $io->info("IntendedUseVegetationCheckCommand - sending notification to user with ID: {$user_to_be_notified_id}"); + NotificationsHandler::dispatch($water_drawing_paperwork->controllable_object_id, 'send_to_last_edit_user_intended_use_check_completed', ['last_edit_user_id' => $user_to_be_notified_id, 'link' => '/water_drawing_paperworks/view' . ($water_drawing_paperwork->scanned ? '_scan' : '') .'/' . $water_drawing_paperwork->id, 'water_drawing_paperwork_id' => $water_drawing_paperwork->id]); + } else { + $io->comment("IntendedUseVegetationCheckCommand - notification_user_id is missing, skipping notification!"); + } + + $io->info("IntendedUseVegetationCheckCommand - JOB ENDED!"); + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php b/idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php new file mode 100644 index 0000000..d793798 --- /dev/null +++ b/idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php @@ -0,0 +1,65 @@ +fetchTable('Applicants')->find()->where(['Applicants.province IN' => ['Palermo', 'Catania', 'Caltanissetta', 'Enna', 'Ragusa', 'Agrigento', 'Messina', 'Siracusa', 'Trapani']])->toArray(); + foreach($applicants as $applicant){ + switch(strtolower($applicant->province)){ + case 'catania': + $province = 'CT'; + break; + case 'palermo': + $province = 'PA'; + break; + case 'caltanissetta': + $province = 'CL'; + break; + case 'enna': + $province = 'EN'; + break; + case 'ragusa': + $province = 'RG'; + break; + case 'siracusa': + $province = 'SR'; + break; + case 'trapani': + $province = 'TP'; + break; + case 'messina': + $province = 'ME'; + break; + case 'agrigento': + $province = 'AG'; + break; + } + if(!isset($province)) continue; + $applicant = $this->fetchTable('Applicants')->patchEntity($applicant, [ + 'province' => $province + ]); + if(!$this->fetchTable('Applicants')->save($applicant, [ + 'checkRules' => false + ])){ + $io->out(__('Errore durante il salvataggio')); + $io->out(json_encode($applicant->getErrors(), JSON_PRETTY_PRINT)); + } + $province = null; + } + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/NotificationsHandlerCommand.php b/idrocap_wa/src/Command/NotificationsHandlerCommand.php new file mode 100644 index 0000000..b185036 --- /dev/null +++ b/idrocap_wa/src/Command/NotificationsHandlerCommand.php @@ -0,0 +1,65 @@ +addArgument('data', [ + 'help' => 'the serialized data to process', + 'required' => true, + ]); + + return $parser; + } + + /** + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): int + { + $data = $args->getArgument('data'); + $io->info("NotificationsHandlerCommand - received data: {$data}"); + + $deserialized_data = json_decode($data, true); + + if (empty($deserialized_data['background_task_id'])) { + $io->abort("NotificationsHandlerCommand - background_task_id is missing!"); + } + + $background_task = $this->fetchTable('BackgroundTasks')->find()->where(['BackgroundTasks.id' => $deserialized_data['background_task_id']])->first(); + if (!$background_task) { + $io->abort("NotificationsHandlerCommand - background_task not found!"); + } + + $request = json_decode($background_task->data, true); + NotificationsHandler::executeDispatch($request['co_id'], $request['notification_code'], $request['options'], $request['group'], $request['user_logged']); + + $io->success("NotificationsHandlerCommand - successfully processed!"); + return static::CODE_SUCCESS; + } +} diff --git a/idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php b/idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php new file mode 100644 index 0000000..9fa732f --- /dev/null +++ b/idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php @@ -0,0 +1,98 @@ +setDescription('Unpacks water_drawing_paperworks from Snapshots and store them to unpacked_water_drawing_paperwork_snapshots table with the last unpacking version number available'); + + $parser + ->addOptions([ + 'limit' => [ + 'short' => 'l', + 'help' => 'Number of rows to process', + 'boolean' => false, + 'required' => true, + ], + ]); + + return $parser; + } + + /** + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $limit = $args->getOption('limit'); + if ($limit < 1) $io->abort("You must specify an Int number greater than ZERO!"); + $io->info("trying processing $limit items..."); + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $io->info("lastWaterDrawingPaperworkUnpackingVersion: $lastWaterDrawingPaperworkUnpackingVersion"); + + $processed = 0; + $unpackable_water_drawing_paperwork_snapshots = $this->fetchTable('Snapshots')->find()->where(['Snapshots.controllable_object_type_id' => 9, 'OR' => ['Snapshots.unpacked_with_version is NULL', 'Snapshots.unpacked_with_version <>' => $lastWaterDrawingPaperworkUnpackingVersion]])->limit((int)$limit)->toArray(); + + $io->info("found " . count($unpackable_water_drawing_paperwork_snapshots) . " unpackable items."); + + if (count($unpackable_water_drawing_paperwork_snapshots) > 0) ConnectionManager::get('default')->begin(); + + $this->fetchTable('WaterDrawingPaperworks')->removeBehavior('Trash'); + + foreach ($unpackable_water_drawing_paperwork_snapshots as $unpackable_water_drawing_paperwork_snapshot) { + $io->info("\nUnpackedWaterDrawingPaperworkSnapshot entity:"); + $unpackedWaterDrawingPaperworkSnapshot = SnapshotsHandler::getUnpackedWaterDrawingPaperworkSnapshot($unpackable_water_drawing_paperwork_snapshot->id); + if (!$unpackedWaterDrawingPaperworkSnapshot) { + ConnectionManager::get('default')->rollback(); + $io->abort("\nError retrieving unpackedWaterDrawingPaperworkSnapshot!"); + } + $io->info(json_encode($unpackedWaterDrawingPaperworkSnapshot)); + $io->info("\nSaving unpacked water_drawing_paperwork snapshot to unpackedWaterDrawingPaperworkSnapshots table..."); + if (!$this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->save($unpackedWaterDrawingPaperworkSnapshot)) { + ConnectionManager::get('default')->rollback(); + $io->abort("\nError saving unpackedWaterDrawingPaperworkSnapshot: " . json_encode($unpackedWaterDrawingPaperworkSnapshot->getErrors())); + } + $io->info("\nMarking and saving snapshot with ID " . $unpackable_water_drawing_paperwork_snapshot->id . " as unpacked with version: " . $lastWaterDrawingPaperworkUnpackingVersion); + $unpackable_water_drawing_paperwork_snapshot->unpacked_with_version = $lastWaterDrawingPaperworkUnpackingVersion; + if (!$this->fetchTable('Snapshots')->save($unpackable_water_drawing_paperwork_snapshot)) { + ConnectionManager::get('default')->rollback(); + $io->abort("\nError saving snapshot: " . json_encode($unpackable_water_drawing_paperwork_snapshot->getErrors())); + } + $processed++; + $io->success("\nSUCCESSFULLY PROCESSED: $processed !\n"); + } + + $this->fetchTable('WaterDrawingPaperworks')->addBehavior('Muffin/Trash.Trash'); + + $io->success("\nJOB IS DONE. REQUESTED: $limit, UNPACKABLE: " . count($unpackable_water_drawing_paperwork_snapshots) . " SUCCESSFULLY PROCESSED: $processed"); + + if (count($unpackable_water_drawing_paperwork_snapshots) > 0) ConnectionManager::get('default')->commit(); + + return static::CODE_SUCCESS; + } +} diff --git a/idrocap_wa/src/Console/Installer.php b/idrocap_wa/src/Console/Installer.php new file mode 100644 index 0000000..6f55798 --- /dev/null +++ b/idrocap_wa/src/Console/Installer.php @@ -0,0 +1,250 @@ +getIO(); + + $rootDir = dirname(__DIR__, 2); + + static::createAppLocalConfig($rootDir, $io); + static::createWritableDirectories($rootDir, $io); + + static::setFolderPermissions($rootDir, $io); + static::setSecuritySalt($rootDir, $io); + + if (class_exists(CodeceptionInstaller::class)) { + CodeceptionInstaller::customizeCodeceptionBinary($event); + } + } + + /** + * Create config/app_local.php file if it does not exist. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function createAppLocalConfig(string $dir, IOInterface $io): void + { + $appLocalConfig = $dir . '/config/app_local.php'; + $appLocalConfigTemplate = $dir . '/config/app_local.example.php'; + if (!file_exists($appLocalConfig)) { + copy($appLocalConfigTemplate, $appLocalConfig); + $io->write('Created `config/app_local.php` file'); + } + } + + /** + * Create the `logs` and `tmp` directories. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function createWritableDirectories(string $dir, IOInterface $io): void + { + foreach (static::WRITABLE_DIRS as $path) { + $path = $dir . '/' . $path; + if (!file_exists($path)) { + mkdir($path); + $io->write('Created `' . $path . '` directory'); + } + } + } + + /** + * Set globally writable permissions on the "tmp" and "logs" directory. + * + * This is not the most secure default, but it gets people up and running quickly. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function setFolderPermissions(string $dir, IOInterface $io): void + { + // ask if the permissions should be changed + if ($io->isInteractive()) { + $validator = function (string $arg): string { + if (in_array($arg, ['Y', 'y', 'N', 'n'])) { + return $arg; + } + throw new Exception('This is not a valid answer. Please choose Y or n.'); + }; + $setFolderPermissions = $io->askAndValidate( + 'Set Folder Permissions ? (Default to Y) [Y,n]? ', + $validator, + 10, + 'Y' + ); + + if (in_array($setFolderPermissions, ['n', 'N'])) { + return; + } + } + + // Change the permissions on a path and output the results. + $changePerms = function (string $path) use ($io): void { + $currentPerms = fileperms($path) & 0777; + $worldWritable = $currentPerms | 0007; + if ($worldWritable == $currentPerms) { + return; + } + + $res = chmod($path, $worldWritable); + if ($res) { + $io->write('Permissions set on ' . $path); + } else { + $io->write('Failed to set permissions on ' . $path); + } + }; + + $walker = function (string $dir) use (&$walker, $changePerms): void { + /** @phpstan-ignore-next-line */ + $files = array_diff(scandir($dir), ['.', '..']); + foreach ($files as $file) { + $path = $dir . '/' . $file; + + if (!is_dir($path)) { + continue; + } + + $changePerms($path); + $walker($path); + } + }; + + $walker($dir . '/tmp'); + $changePerms($dir . '/tmp'); + $changePerms($dir . '/logs'); + } + + /** + * Set the security.salt value in the application's config file. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function setSecuritySalt(string $dir, IOInterface $io): void + { + $newKey = hash('sha256', Security::randomBytes(64)); + static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php'); + } + + /** + * Set the security.salt value in a given file + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @param string $newKey key to set in the file + * @param string $file A path to a file relative to the application's root + * @return void + */ + public static function setSecuritySaltInFile(string $dir, IOInterface $io, string $newKey, string $file): void + { + $config = $dir . '/config/' . $file; + $content = file_get_contents($config); + + /** @phpstan-ignore-next-line */ + $content = str_replace('__SALT__', $newKey, $content, $count); + + if ($count == 0) { + $io->write('No Security.salt placeholder to replace.'); + + return; + } + + $result = file_put_contents($config, $content); + if ($result) { + $io->write('Updated Security.salt value in config/' . $file); + + return; + } + $io->write('Unable to update Security.salt value.'); + } + + /** + * Set the APP_NAME value in a given file + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @param string $appName app name to set in the file + * @param string $file A path to a file relative to the application's root + * @return void + */ + public static function setAppNameInFile(string $dir, IOInterface $io, string $appName, string $file): void + { + $config = $dir . '/config/' . $file; + $content = file_get_contents($config); + /** @phpstan-ignore-next-line */ + $content = str_replace('__APP_NAME__', $appName, $content, $count); + + if ($count == 0) { + $io->write('No __APP_NAME__ placeholder to replace.'); + + return; + } + + $result = file_put_contents($config, $content); + if ($result) { + $io->write('Updated __APP_NAME__ value in config/' . $file); + + return; + } + $io->write('Unable to update __APP_NAME__ value.'); + } +} diff --git a/idrocap_wa/src/Controller/AiServicesController.php b/idrocap_wa/src/Controller/AiServicesController.php new file mode 100644 index 0000000..b2822b2 --- /dev/null +++ b/idrocap_wa/src/Controller/AiServicesController.php @@ -0,0 +1,91 @@ +viewBuilder()->setClassName(JsonView::class); + $this->client = new Client([ + 'timeout' => 120 + ]); + } + + public function autocomplete(): Response + { + if (!$this->request->is('post')) { + $this->respond(405, "Method not allowed"); + } + + $isAiServiceEnabled = Configure::read('App.aiServiceEnabled'); + + if(!$isAiServiceEnabled) { + return $this->respond(403, "AI Service is disabled"); + } + + $request = $this->request->getData(); + $type = $request['type'] ?? null; + $documentHash = $request['documentHash'] ?? null; + + if (!$type || !$documentHash) { + return $this->respond(400, "Missing parameters"); + } + + $attachment = $this->findAttachment($documentHash); + + if (!$attachment) { + return $this->respond(404, "Attachment not found"); + } + + $file_name = $attachment->file_name; + $container_co_id = $attachment->container_controllable_object_id; + $path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + + if ($output === false) { + return $this->respond(404, "File not found or could not be opened"); + } + return $this->callAiServiceAndRespond($request['type'], $request['documentHash'], $output); + } + + private function callAiServiceAndRespond(string $type, string $documentHash, string $fileContent): Response + { + try { + $postData = json_encode([ + 'type' => $type, + 'documentHash' => $documentHash, + 'fileContent' => base64_encode($fileContent), + ]); + $apiResponse = $this->client->post(Configure::read('App.aiServiceUrl'),$postData, ['type' => "json"]); + + if ($apiResponse->isOk()) { + return $this->respond(200, ['result' => $apiResponse->getJson()]); + } else { + return $this->respond($apiResponse->getStatusCode(), "API Error: " . $apiResponse->getStatusCode()); + } + } catch (Exception $e) { + return $this->respond(500, $e->getMessage()); + } + } + + private function findAttachment(string $documentHash): Attachment + { + return $this->fetchTable('Attachments')->find() + ->contain(['ContainerControllableObjects']) + ->where(['file_name' => $documentHash]) + ->first(); + } +} diff --git a/idrocap_wa/src/Controller/Api/AppController.php b/idrocap_wa/src/Controller/Api/AppController.php new file mode 100644 index 0000000..3f4ea42 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/AppController.php @@ -0,0 +1,74 @@ +loadComponent('FormProtection');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + + $this->loadComponent('Authentication.Authentication'); + + $this->logged_user = $this->Authentication->getIdentity(); + $this->nopaginate = $this->request->getQuery('nopaginate') !== null && $this->request->getQuery('nopaginate'); + } + + /** + * respond + * + * @param Int $code + * @param null|Object|Array|String $bodyResponse + * @param String $content + * @return Response + */ + public function respond(Int $code = 200, null|Object|Array|String $bodyResponse = null, String $content = "application/json") : Response + { + $bodyResponse = is_object($bodyResponse) || is_array($bodyResponse) ? $bodyResponse : ['result' => $bodyResponse]; + $response = $this->getResponse(); + $response = $response->withHeader('Access-Control-Allow-Origin', '*'); + $response = $response->withHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT'); + $response = $response->withHeader('Access-Control-Max-Age', '60'); + $response = $response->withHeader('Access-Control-Allow-Headers', 'x-requested-with, Content-Type, origin, authorization, accept, client-security-token'); + return $response->withStringBody(json_encode($bodyResponse))->withStatus($code)->withType($content); + } +} diff --git a/idrocap_wa/src/Controller/Api/AttachmentsController.php b/idrocap_wa/src/Controller/Api/AttachmentsController.php new file mode 100644 index 0000000..0a20053 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/AttachmentsController.php @@ -0,0 +1,53 @@ +respond(400, "not implemented");} + public function add() {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * View method + * + * @param string|null $hash Attachment hash. + * @return \Cake\Http\Response|void + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($hash) + { + $attachment = $this->fetchTable('Attachments')->find() + ->contain(['ContainerControllableObjects']) + ->where(['file_name' => $hash]) + ->first(); + + if (!$attachment) return $this->respond(404, __('Allegato non trovato')); + if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) return $this->respond(403, __('Non hai i permessi necessari per visionare l\'allegato')); + + $mimetype = $attachment->mimetype; + $file_name = $attachment->file_name; + $original_file_name = $attachment->original_file_name; + $container_co_id = $attachment->container_controllable_object_id; + $path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withAddedHeader('Content-Disposition', 'filename="' . $original_file_name . '"') + ->withCharset('UTF-8') + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/Api/ErrorController.php b/idrocap_wa/src/Controller/Api/ErrorController.php new file mode 100644 index 0000000..501e251 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/ErrorController.php @@ -0,0 +1,70 @@ +viewBuilder()->setTemplatePath('Error'); + } + + /** + * afterFilter callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function afterFilter(EventInterface $event) + { + } +} diff --git a/idrocap_wa/src/Controller/Api/NotificationsController.php b/idrocap_wa/src/Controller/Api/NotificationsController.php new file mode 100644 index 0000000..b64bc81 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/NotificationsController.php @@ -0,0 +1,156 @@ +respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $notifications = $this->fetchTable('Notifications')->find() + ->contain(['NotificationTypes']) + ->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) + ->order(['created' => 'DESC']) + ->formatResults(function (\Cake\Collection\CollectionInterface $notifications) { + return $notifications + ->map(function ($notification) { + if ($notification->already_mapped) return $notification; + $notification->already_mapped = true; + $notification->setHidden(array_merge($notification->getHidden(), ['already_mapped'])); + $notification->info = json_decode($notification->info); + $webURL = Configure::read('App.weburl'); + $notification->info->weblink = $webURL . $notification->info->link; + $notification->info->link = '/api' . $notification->info->link; + return $notification; + }); + }); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_notifications = $this->paginate($notifications, [ + 'maxLimit' => 100, + 'limit' => 100, + ]); + return $this->respond(200, ['notifications' => $paginated_notifications, 'pagination' => $paginated_notifications->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + /** + * count + * + * @return \Cake\Http\Response + */ + public function count() + { + $notifications_count = $this->fetchTable('Notifications')->find() + ->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) + ->count(); + return $this->respond(200, ['count' => $notifications_count]); + } + + /** + * add + * + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability(['notifications.read_all'])) { + return $this->respond(403, ['capabilities' => ['notifications.read_all']]); + } + $userId = $this->logged_user->id; + $this->fetchTable('Notifications')->updateAll(['read_by_user' => DateTime::now()], ['read_by_user IS NULL', 'user_id' => $userId]); + return $this->respond(201, "all notifications has been marked as read"); + } + + /** + * edit + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $notification = $this->fetchTable('Notifications')->get($id); + $userId = $this->logged_user->id; + if($notification->user_id != $userId) + { + return $this->respond(403, "access unauthorised"); + } + if($notification->read_by_user) + { + return $this->respond(400, "notification has already been read"); + } + $notification->read_by_user = DateTime::now(); + + if(!$this->fetchTable('Notifications')->save($notification)) + { + return $this->respond(400, ['error' => $notification->getErrors()]); + } + $notification->info = json_decode($notification->info); + return $this->respond(201, ['notification' => $notification]); + } + + public function check() + { + $notifications_count = $this->fetchTable('Notifications')->find() + ->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) + ->count(); + return $this->respond(200, ['result' => $notifications_count != 0]); + + } +} diff --git a/idrocap_wa/src/Controller/Api/OrganisationTypesController.php b/idrocap_wa/src/Controller/Api/OrganisationTypesController.php new file mode 100644 index 0000000..978712d --- /dev/null +++ b/idrocap_wa/src/Controller/Api/OrganisationTypesController.php @@ -0,0 +1,31 @@ +respond(400, "not implemented");} + public function view($id = null) {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $organisationTypes = $this->fetchTable('OrganisationTypes')->find('list')->order(['OrganisationTypes.description' => 'ASC']); + return $this->respond(200, ['organisation_types' => $organisationTypes]); + } +} diff --git a/idrocap_wa/src/Controller/Api/OrganisationsController.php b/idrocap_wa/src/Controller/Api/OrganisationsController.php new file mode 100644 index 0000000..00c726c --- /dev/null +++ b/idrocap_wa/src/Controller/Api/OrganisationsController.php @@ -0,0 +1,157 @@ +respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $options = ['type' => $this->request->getQuery('type') ?? null]; + + $user_can_index = $this->fetchTable('Organisations')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + + $organisations = $this->fetchTable('Organisations') + ->find($options['finder'], params: $options) + ->contain(['Actors', 'OrganisationTypes']) + ->formatResults(function (\Cake\Collection\CollectionInterface $organisations) { + return $organisations + ->map(function ($organisation) { + if ($organisation->already_mapped) return $organisation; + $organisation->already_mapped = true; + $organisation->setHidden(array_merge($organisation->getHidden(), ['already_mapped', 'phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); + $organisation->actor->setHidden(array_merge($organisation->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + return $organisation; + }); + }); + + $organisations = $this->fetchTable('Organisations')->applySearchParams($organisations, $this->request->getQueryParams()); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_organisations = $this->paginate($organisations, [ + 'maxLimit' => 100, + 'limit' => 100, + 'sortableFields' => ['Actors.description', 'OrganisationTypes.description', 'acronym', 'address', 'district', 'cap', 'province'], + 'order' => [ + 'Actors.description' => 'ASC' + ], + ]); + return $this->respond(200, ['organisations' => $paginated_organisations, 'pagination' => $paginated_organisations->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id = null) + { + $options = []; + + $organisation = $this->fetchTable('Organisations')->get($id, contain: ['Actors', 'OrganisationTypes']); + + $organisation->setHidden(array_merge($organisation->getHidden(), ['phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); + $organisation->actor->setHidden(array_merge($organisation->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + + if (($this->logged_user->organisation_id == $id) && (!$organisation->can_view($this->logged_user, $options))) { + return $this->respond(403, $options['error']); + } + + $organisation->deliveries = $organisation->actor->getContactsList(); + + return $this->respond(200, ['organisation' => $organisation]); + } + + /** + * getPhoto + * + * @param String $file_name + * @return \Cake\Http\Response + */ + public function getPhoto($file_name) + { + $options = []; + + $organisation = $this->fetchTable('Organisations')->find() + ->where(['Organisations.photo' => $file_name]) + ->first(); + + if (!$organisation) { + return $this->respond(404, __('Organizzazione non trovata!')); + } + if (!$organisation->can_view($this->logged_user, $options)) { + return $this->respond(403, $options['error']); + } + + $mimetype = "image/jpeg"; + $path = Configure::read('App.organisationPhotoPath') . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/Api/SubscriptionsController.php b/idrocap_wa/src/Controller/Api/SubscriptionsController.php new file mode 100644 index 0000000..31c1b5f --- /dev/null +++ b/idrocap_wa/src/Controller/Api/SubscriptionsController.php @@ -0,0 +1,67 @@ +respond(400, "not implemented");} + public function view($id = null) {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * subscribe + * + * @return \Cake\Http\Response + */ + public function subscribe() + { + $token = $this->request->getData('token') ?? null; + if (empty($token)) { + return $this->respond(400, ['error' => 'invalid subscribe token']); + } + $push_notification = $this->fetchTable('PushNotifications') + ->newEntity([ + 'value' => $token, + 'enable_notifications' => true, + 'delivery' => [ + 'actor_id' => $this->logged_user->actor_id, + 'delivery_type_id' => 0, + ], + ]); + + $result = $this->fetchTable('PushNotifications')->save($push_notification); + $status_code = is_object($result) && get_class($result) === "App\Model\Entity\PushNotification" ? 201 : 400; + $message = $status_code == 201 ? $push_notification : $push_notification->getErrors(); + return $this->respond($status_code, ['result' => $message]); + } + + /** + * unsubscribe + * + * @return \Cake\Http\Response + */ + public function unsubscribe() + { + $user_push_notification_tokens = $this->fetchTable('Deliveries') + ->find() + ->where(['Deliveries.actor_id' => $this->logged_user->actor_id, 'Deliveries.delivery_type_id' => 0]) + ->all(); + + foreach ($user_push_notification_tokens as $user_push_notification_token) { + if (!$this->fetchTable('Deliveries')->delete($user_push_notification_token)) { + return $this->respond(500, ['result' => $user_push_notification_token->getErrors()]); + } + } + return $this->respond(200, ['unsubscribed' => $user_push_notification_tokens->count()]); + } +} diff --git a/idrocap_wa/src/Controller/Api/UsersController.php b/idrocap_wa/src/Controller/Api/UsersController.php new file mode 100644 index 0000000..aa9e433 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/UsersController.php @@ -0,0 +1,230 @@ +Authentication->allowUnauthenticated(['login']); + } + + public function add() {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $options = []; + + $user_can_index = $this->fetchTable('Users')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + + $users = $this->fetchTable('Users') + ->find($options['finder'], params: $options) + ->contain(['UserActors', 'Organisations' => ['Actors']]) + ->formatResults(function (\Cake\Collection\CollectionInterface $users) { + return $users + ->map(function ($user) { + if ($user->already_mapped) return $user; + $user->already_mapped = true; + $user->setHidden(array_merge($user->getHidden(), ['already_mapped', 'organisation_id', 'phone', 'mobile', 'mobile2', 'email', 'notification_hash', 'fax', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'language_id', 'privacy', 'conditions', 'password_recovery_token', 'last_change_password', 'password_recovery_counter', 'email2', 'actor_id', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd'])); + $user->user_actor->setHidden(array_merge($user->user_actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + $user->organisation_description = $user->organisation->actor->description; + $user->birthday = $user->birthday?->format('d/m/Y'); + return $user; + }); + }); + + $users = $this->fetchTable('Users')->applySearchParams($users, $this->request->getQueryParams()); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_users = $this->paginate($users, [ + 'maxLimit' => 100, + 'limit' => 100, + 'sortableFields' => ['UserActors.description', 'username', 'surname', 'name', 'cap', 'gender'], + 'order' => [ + 'Users.surname' => 'ASC', + ], + ]); + return $this->respond(200, ['users' => $paginated_users, 'pagination' => $paginated_users->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id) + { + $options = []; + + $user = $this->fetchTable('Users')->get($id, contain: ['UserActors', 'Organisations' => ['Actors', 'OrganisationTypes']]); + + if ($user->id != $this->logged_user->id && (!$user->can_view($this->logged_user, $options))) { + return $this->respond(403, $options['error']); + } + + $user->setHidden(array_merge($user->getHidden(), ['fax', 'email', 'mobile2', 'mobile', 'email2', 'phone', 'organisation_id', 'notification_hash', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'language_id', 'privacy', 'conditions', 'password_recovery_token', 'last_change_password', 'password_recovery_counter', 'actor_id', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd'])); + $user->actor = $user->user_actor; + unset($user->user_actor); + $user->actor->setHidden(array_merge($user->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + $user->organisation_description = null; + if ($user->hasValue('organisation')) { + $user->organisation->setHidden(array_merge($user->organisation->getHidden(), ['phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); + $user->organisation_description = $user->organisation->actor->description; + unset($user->organisation->actor); + } + + $user->deliveries = $user->actor->getContactsList(); + + return $this->respond(200, ['user' => $user]); + } + + + /** + * login + * + * @return \Cake\Http\Response + */ + public function login() + { + $result = $this->Authentication->getResult(); + // If the user is logged in send them away. + if ($result->isValid()) { + $receivedData = $this->getRequest()->getData(); + $client_id = isset($receivedData['client_id']) && $receivedData['client_id'] != "" ? $receivedData['client_id'] : 'auto-' . bin2hex(random_bytes(32)); + $platform = isset($receivedData['platform']) ? $receivedData['platform'] : 'unknown'; + $tokenExpirationTime = Configure::read('App.jwt.expiration_time'); + + $token = JWT::encode([ + 'sub' => $this->Authentication->getIdentity()->get('username'), + 'user_id' => $this->Authentication->getIdentity()->get('id'), + 'exp' => time() + $tokenExpirationTime, + 'client_id' => $client_id, + 'platform' => $platform, + ], file_get_contents(Configure::read('App.jwt.keys.private')), Configure::read('App.jwt.algorithm')); + + $user = $this->fetchTable('Users')->get($this->Authentication->getIdentity()->get('id')); + $user->setHidden(['password', 'phone', 'mobile', 'mobile2', 'email', 'mobile_token_date', 'mobile_token', 'notification_hash', 'fax', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'position', 'position_date', 'ask_new_password', 'password_expiration', 'password_recovery_token', 'password_recovery_counter', 'email2', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd', 'make_volunteer', 'full_name', 'capabilities']); + + $user->mobile_menu = $this->fetchTable('MobileComponents') + ->find() + ->matching('Capabilities') + ->where(['Capabilities.id IN' => $user->getCapabilityIds(true)]) + ->order(['MobileComponents.id' => 'ASC']) + ->distinct(['MobileComponents.menu_item']) + ->select('MobileComponents.menu_item') + ->toArray(); + + $user->notifications = $this->fetchTable('Notifications')->find() + ->contain(['NotificationTypes']) + ->where(['user_id' => $user->id, 'read_by_user IS NULL']) + ->order(['created' => 'DESC']) + ->formatResults(function (\Cake\Collection\CollectionInterface $notifications) { + return $notifications + ->map(function ($notification) { + $notification->info = json_decode($notification->info); + $webURL = Configure::read('App.weburl'); + $notification->info->weblink = $webURL . $notification->info->link; + $notification->info->link = '/api' . $notification->info->link; + return $notification; + }); + })->count() != 0; + return $this->respond(200, ['token' => $token, 'user' => $user, 'mobile_menu' => $user->mobile_menu]); + } + if ($this->request->is('post')) { + return $this->respond(401, ['error' => 'invalid credentials']); + } + } + + /** + * getPhoto + * + * @param String $file_name + * @return \Cake\Http\Response + */ + public function getPhoto($file_name) + { + $options = []; + + $user = $this->fetchTable('Users')->find() + ->where(['Users.photo' => $file_name]) + ->first(); + + if (!$user) { + return $this->respond(404, __('Utente non trovato!')); + } + if (!$user->can_view($this->logged_user, $options)) { + return $this->respond(403, $options['error']); + } + + $mimetype = "image/jpeg"; + $path = Configure::read('App.organisationPhotoPath') . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php b/idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php new file mode 100644 index 0000000..e420203 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php @@ -0,0 +1,75 @@ +fetchTable('WaterDrawingDerivations')->find()->where(['WaterDrawingDerivations.id' => $id])->first(); + if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); + return $this->respond(200, ['WaterDrawingDerivation' => $waterDrawingDerivation]); + } + + public function update_data(){ + $data = $this->request->getData(); + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->where(['WaterDrawingDerivations.id' => $data['water_drawing_derivation_id']])->first(); + if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ + 'annual_volume' => $data['volume'], + 'average_flow_rate' => $data['portata'] + ]); + if($this->fetchTable('WaterDrawingDerivations')->save($waterDrawingDerivation)){ + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + return $this->respond(200, ['message' => $waterDrawingDerivation]); + }else{ + return $this->respond(500, ['message' => 'KO', 'error' => $waterDrawingDerivation->getErrors()]); + } + } + + public function update_location(){ + $data = $this->request->getData(); + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->contain(['WaterDrawingPaperworks'])->where(['WaterDrawingDerivations.id' => $data['water_drawing_derivation_id']])->first(); + if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}'; + if(!GeoValidation::isValidGeometry(json_decode($feature_collection))) return $this->respond(500, ['message' => 'Punto di derivazione non valido.']); + $reverse_geocoding = Geocoding::performGeocoding('reverse', ['format' => 'json', 'namedetails' => '1', 'lat' => $data['latitude'], 'lon' => $data['longitude']]); + if($reverse_geocoding['status_code']['http_code'] == '200'){ + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ + 'latitude' => $data['latitude'], + 'longitude' => $data['longitude'], + 'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}', + 'location' => isset($reverse_geocoding['contents']['address']['road']) ? $reverse_geocoding['contents']['address']['road'] : '', + 'district' => isset($reverse_geocoding['contents']['address']['town']) ? $reverse_geocoding['contents']['address']['town'] : '', + 'description' => isset($reverse_geocoding['contents']['display_name']) ? $reverse_geocoding['contents']['display_name'] : '' + ]); + }else{ + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ + 'latitude' => $data['latitude'], + 'longitude' => $data['longitude'], + 'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}' + ]); + } + if($this->fetchTable('WaterDrawingDerivations')->save($waterDrawingDerivation)){ + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + return $this->respond(200, ['message' => 'OK']); + }else{ + return $this->respond(500, ['message' => 'KO', 'error' => $waterDrawingDerivation->getErrors()]); + } + } +} diff --git a/idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php b/idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php new file mode 100644 index 0000000..ac2a04f --- /dev/null +++ b/idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php @@ -0,0 +1,47 @@ +request->getData(); + $WaterDrawingMeasurement = $this->fetchTable('WaterDrawingMeasurements')->newEntity([ + 'volume' => $data['volume'], + 'water_drawing_meter_id' => $data['water_drawing_meter_id'], + 'date' => DateTime::now(), + 'user_id' => $this->logged_user->id + ]); + if($this->fetchTable('WaterDrawingMeasurements')->save($WaterDrawingMeasurement)){ + $waterDrawingMeter = $this->fetchTable('WaterDrawingMeters')->get($data['water_drawing_meter_id'], contain: ['WaterDrawingIntendedUses' => ['WaterDrawingPaperworks']]); + SnapshotsHandler::createSnapshot($waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork->controllable_object_id); + return $this->respond(200, ['message' => __('Salvato con successo')]); + }else{ + return $this->respond(500, ['message' => __('Errore durante il salvataggio.'), 'error' => $WaterDrawingMeasurement->getErrors()]); + } + } + + public function last_index($id){ + $WaterDrawingMeasurements = $this->fetchTable('WaterDrawingMeasurements')->find()->contain(['Users'])->where(['WaterDrawingMeasurements.water_drawing_meter_id' => $id])->order(['WaterDrawingMeasurements.date' => 'DESC', 'WaterDrawingMeasurements.id' => 'DESC'])->limit(5)->formatResults( function ($result){ + return $result->map( function ($q) { + $q->date = $q->date?->format('d/m/Y'); + return $q; + }); + })->toArray(); + return $this->respond(200, ['WaterDaringMeasurements' => $WaterDrawingMeasurements]); + } +} diff --git a/idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php b/idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php new file mode 100644 index 0000000..23dcb00 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php @@ -0,0 +1,170 @@ +fetchTable('WaterDrawingPaperworks')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + + $waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->find() + ->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses'])->matching('Applicants'); + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperworks = $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); + } + $waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->applySearchParams($waterDrawingPaperworks, $this->request->getQueryParams()); + + $waterDrawingPaperworks = $waterDrawingPaperworks->distinct(['WaterDrawingPaperworks.id'])->formatResults(function ($results){ + return $results->map(function ($row) { + if ($row->already_mapped) return $row; + $row->already_mapped = true; + $row->setHidden(array_merge($row->getHidden(), ['already_mapped'])); + $row->release_date = $row->release_date?->format('d/m/Y'); + $row->expiration_date = $row->expiration_date?->format('d/m/Y'); + $row->controllable_object->created = $row->controllable_object->created?->format('d/m/Y H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('d/m/Y H:i:s'); + return $row; + }); + }); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_waterDrawingPaperworks = $this->paginate($waterDrawingPaperworks, [ + 'maxLimit' => 25, + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + ]); + return $this->respond(200, ['waterDrawingPaperworks' => $paginated_waterDrawingPaperworks, 'pagination' => $paginated_waterDrawingPaperworks->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + public function view($id){ + $options = []; + + $user_can_index = $this->fetchTable('WaterDrawingPaperworks')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + $organisation = $this->getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $this->logged_user->organisation_id])->first(); + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->find() + ->contain([ 'WaterDrawingArticles', 'WaterDrawingFees', 'GcUsers' => ['Organisations'], 'DrarUsers' => ['Organisations'], 'WaterDrawingReturnPoints', 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], 'WaterDrawingPaperworkStatuses', 'ControllableObjects' => ['Attachments' => ['Tags']], 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q){ + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + ]); + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperwork = $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); + } + $waterDrawingPaperwork = $waterDrawingPaperwork->where(['WaterDrawingPaperworks.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) use ($organisation){ + return $results->map(function ($row) use ($organisation){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && ( $this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5 ) || ( $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4 )); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete'); + $row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && $row->water_drawing_paperwork_status_id === -3; + $row->can_send_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && $row->water_drawing_paperwork_status_id === -1 && $row->check_sdd && $row->gc_user_id == $this->logged_user->id; + $row->can_send_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && $row->water_drawing_paperwork_status_id === -4 && $row->check_dec && $row->drar_user_id == $this->logged_user->id; + $row->can_assign_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && $row->water_drawing_paperwork_status_id <= -2 && $organisation->organisation_type_id == 6; + $row->can_assign_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && isset($row->gc_user->organisation->organisation_type_id) && $organisation->organisation_type_id == $row->gc_user->organisation->organisation_type_id; + if($row->water_drawing_paperwork_status_id === -5){ + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment') ; + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_add_meter = $this->logged_user->hasCapability('documentation.water_drawing_meters.add'); + $row->can_add_measurements = $this->logged_user->hasCapability('documentation.water_drawing_measurements.add'); + $row->can_view_measurements = true; + } + if($row->water_drawing_paperwork_status_id == -4){ + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment') ; + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_submit_antimafia_request = ($this->logged_user->id == $row->drar_user_id) && (!isset($row->water_drawing_antimafia_certification_requests[0])); + $row->can_antimafia_request_to_anac = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($row->water_drawing_antimafia_certification_requests[0]) && ($row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1)); + $row->can_request_self_certification = ($this->logged_user->id == $row->drar_user_id) && (isset($row->water_drawing_antimafia_certification_requests[0]) && (new DateTime($row->water_drawing_antimafia_certification_requests[0]->created))->diffInDays(\Cake\I18n\DateTime::now()) > 30); + $row->can_upload_antimafia_attachment = (isset($row->water_drawing_antimafia_certification_requests[0]) && ( + ( ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && !($row->check_dam)) || + ( ($this->logged_user->id == $row->gc_user_id) && $row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) + )); + } + return $row; + }); + })->first(); + $waterDrawingPaperwork->water_drawing_meters = $this->getTableLocator()->get('WaterDrawingMeters')->find()->contain(['WaterDrawingIntendedUses', 'WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q){ + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }])->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'WaterDrawingMeters.removal_date IS NULL'])->formatResults(function ($results){ + return $results->map(function ($row){ + $row->installation_date = $row->installation_date?->format('d/m/Y'); + return $row; + }); + })->toArray(); + return $this->respond(200, ['result' => $waterDrawingPaperwork]); + } +} diff --git a/idrocap_wa/src/Controller/AppController.php b/idrocap_wa/src/Controller/AppController.php new file mode 100644 index 0000000..69ef6df --- /dev/null +++ b/idrocap_wa/src/Controller/AppController.php @@ -0,0 +1,424 @@ +loadComponent('FormProtection');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + + $this->loadComponent('Authentication.Authentication'); + $this->loadComponent('Flash'); + + // recuperiamo l'entità dello user (se loggato): + $this->logged_user = $this->Authentication->getIdentity(); + + // settiamo il locale come da preferenze utente (se specificato, altrimenti ci pensa il LocaleSelectorMiddleware): + if (!empty($this->logged_user->language_id)) I18n::setLocale($this->fetchTable('Languages')->get($this->logged_user->language_id)->language_code); + $this->set('locale', I18n::getLocale()); + + /* + * Enable the following component for recommended CakePHP form protection settings. + * see https://book.cakephp.org/4/en/controllers/components/form-protection.html + */ + //$this->loadComponent('FormProtection'); + } + + public function beforeRender(EventInterface $event) + { + if ($this->getRequest()->is(['json', 'xml', 'csv'])) { + $this->viewBuilder()->disableAutoLayout(); + } + + $sys_admin_menu_items = null; + $menu_sections = []; + $menu_items = []; + $logged_user_id = null; + $logged_user_description = null; + $logged_user_access_type_description = null; + $logged_user_timezone = null; + $logged_user_organisation_description = null; + $logged_user_photo = Configure::read('App.defaultUserPhoto'); + $user_notifications_count = 0; + $user_notifications = []; + + // bisogna recuperare le capabilities utente (se esiste un utente loggato) + if ($this->logged_user) { + // menu SYSADMIN da mostrare solo ai SYSADMIN: + $sys_admin_menu_items = [ + [ + 'title' => __('SYSADMIN'), + 'icon' => 'lock', + 'menu_items' => [ + [ + 'title' => __('Gestione competenze'), + 'icon' => 'wrench', + 'link' => '/capabilities', + ], + [ + 'title' => __('Test notifiche'), + 'icon' => 'bell', + 'link' => '/notifications/testAll', + 'confirm' => __('Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?'), + 'method' => 'POST', + ], + ], + + ], + ]; + if (!$this->logged_user->sys_admin) $sys_admin_menu_items = null; + + $logged_user_id = $this->logged_user->id; + $logged_user_description = $this->logged_user->name . ' ' . $this->logged_user->surname; + $logged_user_access_type_description = $this->logged_user->sys_admin ? 'sys_admin' : ($this->logged_user->passepartout ? 'passepartout' : ''); + $logged_user_timezone = $this->logged_user->timezone ?? Configure::read('App.defaultUserTimezone'); + if (isset($this->logged_user->organisation_id)) { + $logged_user_organisation_description = $this->fetchTable('Organisations')->get($this->logged_user->organisation_id, contain: ['Actors'])->actor->description; + } + if (!empty($this->logged_user->photo)) $logged_user_photo = Configure::read('App.userPhotoSrc') . "/" . $this->logged_user->photo; + + $user_notifications_count = $this->fetchTable('Notifications')->find()->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL'])->count(); + + $user_notifications = $this->fetchTable('Notifications') + ->find() + ->contain('NotificationTypes') + ->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) + ->order(['Notifications.created' => 'DESC']) + ->all() + ->reduce(function ($acc, $user_notification) { + $notification_info = json_decode($user_notification->info); + $body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; + $icon = $user_notification->notification_type->icon ?? 'bell'; + $time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); + $acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; + return $acc; + }, []); + + $user_capabilityIds_query = $this->logged_user->getCapabilityIds(true); + + $menu_sections_subquery = $this->fetchTable('MenuSections') + ->find() + ->select(['MenuSections.id']) + ->innerJoinWith('Capabilities') + ->where(['Capabilities.id IN' => $user_capabilityIds_query]) + ->distinct(['MenuSections.id']); + + $menu_sections = $this->fetchTable('MenuSections') + ->find() + ->where(['MenuSections.id IN' => $menu_sections_subquery]) + ->order(['MenuSections.id' => 'ASC']) + ->toArray(); + + if (count($menu_sections) > 0) { + // questo blocco controlla se nella request è presente il query param 'menu_section' + // se è presente e rappresenta un id di menu_section valido, lo settiamo in sessione utente + if ($this->getRequest()->getQuery('menu_section')) { + $valid_user_menu_section = $this->fetchTable('MenuSections')->find() + ->matching('Capabilities') + ->where(['Capabilities.id IN' => $user_capabilityIds_query, 'MenuSections.id' => $this->getRequest()->getQuery('menu_section')]) + ->first(); + + $valid_user_menu_section_id = $valid_user_menu_section ? $valid_user_menu_section->id : $menu_sections[0]->id; + + $this->getRequest()->getSession()->write('menu_section', $valid_user_menu_section_id); + } + $menu_section_id = $this->getRequest()->getSession()->read('menu_section') ?? $menu_sections[0]->id; + + $menu_items_subquery = $this->fetchTable('MenuItems') + ->find() + ->select(['MenuItems.id']) + ->innerJoinWith('Capabilities') + ->where(['Capabilities.id IN' => $user_capabilityIds_query]) + ->where(['MenuItems.menu_item_id IS NULL']) + ->where(['MenuItems.menu_section_id' => $menu_section_id]) + ->distinct(['MenuItems.id']); + + $menu_items = $this->fetchTable('MenuItems') + ->find() + ->where(['MenuItems.id IN' => $menu_items_subquery]) + ->order(['MenuItems.menu_order' => 'ASC']) + ->toArray(); + } + + if( $this->request->getPath() !== '/notifications/index' ) + { + $privacy = $this->fetchTable('Privacy') + ->find()->orderBy(['created' => 'DESC']) + ->first(); + + if(isset($privacy)) + { + $hasAcceptedPrivacy = $this->fetchTable('PrivacyUsers')->find()->where([ + 'PrivacyUsers.user_id' => $this->logged_user->id, + 'PrivacyUsers.privacy_id' => $privacy->id + ])->first(); + + if( + !isset($hasAcceptedPrivacy) && + $this->request->getParam('controller') != 'Privacy' && + $this->request->getParam('action') != 'accept_privacy' + ) { + return $this->redirect(['controller' => 'Privacy', 'action' => 'accept_privacy']); + } + } + } + } + + $this->set('menu_sections', $menu_sections); + $this->set('menu_items', $menu_items); + $this->set('sys_admin_menu_items', $sys_admin_menu_items); + $this->set('logged_user_id', $logged_user_id); + $this->set('logged_user_description', $logged_user_description); + $this->set('logged_user_access_type_description', $logged_user_access_type_description); + $this->set('logged_user_timezone', $logged_user_timezone); + $this->set('logged_user_organisation_description', $logged_user_organisation_description); + $this->set('logged_user_photo', $logged_user_photo); + $this->set('user_notifications_count', $user_notifications_count); + $this->set('user_notifications', $user_notifications); + } + + /** + * gen_random_code + * + * @param Int $length + * @return String + */ + protected function gen_random_code(Int $length): String { + $characters = "abcdefghijklmnopqrstuvwxyzABCDERFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $randomString = ""; + + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[mt_rand(0, strlen($characters)-1)]; + } + return $randomString; + } + + /** + * sendNotifications + * + * @param Int|Null $co_id + * @param String $notification_code + * @param Array $options + * @return void + */ + protected function sendNotifications(Int|Null $co_id, String $notification_code, Array $options) + { + NotificationsHandler::dispatch($co_id, $notification_code, $options, null, $this->logged_user->id ?? null); + } + + /** + * applyFilters + * + * @param Query $query + * @return Query + */ + protected function applyFilters(Query $query): Query + { + // recuperiamo i parametri per costruire la chiave per memorizzare i filtri in sessione. + // i filtri sono "scoped" per utente e per route. Quindi per ogni utente possiamo memorizzare + // filtri relativi a più liste. + $logged_user_id = $this->logged_user->id; + $controller = $this->request->getParam('controller'); + $action = $this->request->getParam('action'); + $filter_session_key = "filters-$logged_user_id-$controller-$action"; + + // recuperiamo i filtri o dal POST data (significa che sono stati appena applicati) + // o dalla sessione (se ci sono): + $filters = $this->request->is('post') ? $this->request->getData('filters') : $this->request->getSession()->read($filter_session_key); + \Cake\Log\Log::write("debug", 'applyFilters - ' . ($this->request->is('post') ? 'POST received' : 'SESSION retrieved') . ' filters: ' . json_encode($filters)); + + // ripuliamo i filtri eliminando prima i valori non validi per ciascun filtro + // e successivamente eliminiamo direttamente i fitri che non hanno valori validi (rimasti): + $filters = collection($filters ?? []) + ->map(function ($filter_values, $filter_id) { + return collection($filter_values) + ->filter(function ($filter_value) { + // il controllo con === "0" serve per evitare che il sanitiser elimini + // il valore "0" per filtri di tipo "bool" + return !empty($filter_value) || $filter_value === "0"; + }) + ->reduce(function ($filter_values, $filter_value) { + $filter_values[] = $filter_value; + return $filter_values; + }, []); + }) + ->filter(function ($filter_values, $filter_id) { + return !empty($filter_values); + }) + ->toArray(); + + \Cake\Log\Log::write("debug", 'applyFilters - SANITISED filters: ' . json_encode($filters)); + + // se non si è riusciti a recuperare filtri + // o è stato richesto un reset dei filtri tramite POST + // o non ne sono rimasti a seguito della sanitizzazione, + // cancelliamo comunque la sessione alla chiave $filter_session_key + // ed usciamo senza applicare nulla alla query: + if (empty($filters)) { + \Cake\Log\Log::write("debug", "applyFilters - DELETING DATA SESSION with key '$filter_session_key'"); + $this->request->getSession()->delete($filter_session_key); + \Cake\Log\Log::write("debug", 'applyFilters - NO filters to appply!'); + return $query; + } + + // se abbiamo filtri validi e li abbiamo appena ricevuti (POST), li salviamo in sessione: + if ($this->request->is('post')) { + \Cake\Log\Log::write("debug", "applyFilters - WRITING DATA SESSION with key '$filter_session_key': " . json_encode($filters)); + $this->request->getSession()->write($filter_session_key, $filters); + } + + // array delle possibili associations da gestire nella query con ->leftJoinWith(). + // verrà popolato durante il processo di conversione da filtri a conditions: + $associations = []; + + // array delle conditions creato a partire dai filters ricevuti, da gestire nella query con ->where() + $conditions = collection($filters) + // qui trasformiamo i filtri in conditions in base alla tipologia di filtro ricevuto: + ->map(function ($filter_values, $filter_id) use (&$associations) { + // recuperiamo le info sul filtro dalla table 'filters' avendo ricevuto l'id del filtro: + $filter = $this->fetchTable('Filters')->get((Int)explode("filter_id_", $filter_id)[1]); + // creazione della condizione in base al tipo di filtro: + switch ($filter->filter_type) { + case 'class': + case 'bool': + $condition = [$filter->search . ' IN' => $filter_values]; + break; + case 'text': + $condition = collection($filter_values) + ->map(function ($filter_value) use ($filter) { + return [$filter->search . ' LIKE' => $filter_value]; + }) + ->reduce(function ($conditions, $condition) { + $conditions['OR'][] = $condition; + return $conditions; + }, ['OR' => []]); + break; + case 'date': + $condition = collection($filter_values) + ->map(function ($filter_value) use ($filter) { + $date_array = explode(" - ", $filter_value); + $from_date = $date_array[0]; + $to_date = $date_array[1]; + return [$filter->search . ' >=' => $from_date, $filter->search . ' <=' => $to_date]; + }) + ->reduce(function ($conditions, $condition) { + $conditions['OR'][] = $condition; + return $conditions; + }, ['OR' => []]); + break; + default: + break; + } + // se il filtro è stato gestito e richiede una association, la inseriamo in apposito array: + if (!empty($condition) && !empty($filter->associations)) $associations[] = $filter->associations; + + // se il filtro non è stato gestito, restituiamo null; altrimenti restituiamo la condition + return $condition ?? null; + }) + // qui eliminiamo eventuali conditions null (generate da filtri non (al momento) gestiti: + ->filter(function ($condition) { + return !empty($condition); + }) + // infine restituiamo l'array_values delle conditions ottenute: + ->reduce(function ($conditions, $condition) { + $conditions[] = $condition; + return $conditions; + }, []); + + \Cake\Log\Log::write("debug", 'applyFilters - conditions applied: ' . json_encode($conditions)); + + if (count($conditions) > 0) $query = $query->where($conditions); + + \Cake\Log\Log::write("debug", 'applyFilters - associations applied: ' . json_encode($associations)); + + foreach ($associations as $association) { + $query = $query->leftJoinWith($association); + } + + if (count($associations) > 0) { + $main_table = $query->getRepository()->getAlias(); + $query = $query->distinct(["$main_table.id"]); + \Cake\Log\Log::write("debug", 'applyFilters - distinct applied: ' . "$main_table.id"); + } + + return $query; + } + + /** + * Respond with JSON + * + * @param int $statusCode HTTP status code + * @param null|object|array|string|null $responseBody Content of the response + * @param string $contentType Content type of the response, default "application/json" + * @return Response + */ + public function respond(int $statusCode = 200, null|object|array|string $responseBody = null, string $contentType = "application/json") : Response + { + $responseBody = is_object($responseBody) || is_array($responseBody) ? $responseBody : ['result' => $responseBody]; + + if ($paging = $this->request->getAttribute('paging')) { + $responseBody['pagination'] = $paging; + } + + try { + $encodedBody = json_encode($responseBody, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } catch (Exception $e) { + return $this->getResponse() + ->withStatus(500) + ->withStringBody(json_encode(['error' => 'Failed to encode JSON response'])) + ->withType('application/json'); + } + + $response = $this->getResponse() + ->withStatus($statusCode) + ->withType($contentType) + ->withStringBody($encodedBody); + + return $response; + } +} diff --git a/idrocap_wa/src/Controller/ApplicantsController.php b/idrocap_wa/src/Controller/ApplicantsController.php new file mode 100644 index 0000000..cf643ae --- /dev/null +++ b/idrocap_wa/src/Controller/ApplicantsController.php @@ -0,0 +1,112 @@ +viewBuilder()->setClassName('Json'); + + $search = $this->request->getQueryParams('term'); + $applicants = $this->Applicants->find()->where([ + 'Applicants.tax_code LIKE "%' . $search['term'] . '%" OR Applicants.name LIKE "%' . $search['term'] . '%" OR Applicants.surname LIKE "%' . $search['term'] . '%"' + ])->formatResults(function ($results){ + return $results->map(function ($row) { + return ['id' => $row->id, 'text' => $row->tax_code . ' - ' . $row->name . ' ' . $row->surname]; + }); + })->toArray(); + $this->set(compact('applicants')); + $this->viewBuilder()->setOption('serialize', ['applicants'])->setOption('jsonOptions', JSON_FORCE_OBJECT); + } + + public function get_applicant($id){ + $applicant = $this->Applicants->get($id); + $this->set(compact('applicant')); + $this->viewBuilder()->setOption('serialize', ['applicant'])->setOption('jsonOptions', JSON_FORCE_OBJECT); + } + + public function edit($id, $water_id = null){ + $applicant = $this->Applicants->get($id); + if ($this->request->is(['patch', 'post', 'put'])) { + $applicant = $this->Applicants->patchEntity($applicant, $this->request->getData()); + if ($this->Applicants->save($applicant)) { + $this->Flash->success(__('Il concessionario è stato aggiornato correttamente.')); + + return $this->redirect(['action' => 'view', $id]); + } + $this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); + } + if(isset($water_id)){ + $waterDrawingPaperwork = $this->Applicants->WaterDrawingPaperworks->get($water_id); + $this->set(compact('waterDrawingPaperwork')); + } + $this->set(compact('applicant')); + } + + public function view($id){ + $applicant = $this->Applicants->get($id); + $this->set(compact('applicant')); + } + + // CITIZEN SECTION + + public function citizen_add(){ + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $applicant = $this->Applicants->newEmptyEntity(); + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['name'] = $this->logged_user->name; + $data['surname'] = $this->logged_user->surname; + $data['tax_code'] = $this->logged_user->tax_code; + $applicant = $this->Applicants->patchEntity($applicant, $data); + if ($this->Applicants->save($applicant)) { + $this->Flash->success(__('Il concessionario è stato creato correttamente.')); + + return $this->redirect(['action' => 'citizen_view']); + } + $this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); + } + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $this->set('user', $user); + $this->set(compact('applicant')); + } + + public function citizen_edit(){ + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $applicant = $this->Applicants->find()->where(['Applicants.tax_code' => $user->tax_code])->first(); + if ($this->request->is(['patch', 'post', 'put'])) { + $applicant = $this->Applicants->patchEntity($applicant, $this->request->getData()); + if ($this->Applicants->save($applicant)) { + $this->Flash->success(__('Il concessionario è stato aggiornato correttamente.')); + + return $this->redirect(['action' => 'citizen_view']); + } + $this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); + } + $this->set('user', $user); + $this->set(compact('applicant')); + } + + public function citizen_view(){ + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $applicant = $this->Applicants->find()->where(['Applicants.tax_code' => $user->tax_code])->first(); + if(!isset($applicant)) $this->redirect(['action' => 'citizen_add']); + $this->set(compact('applicant')); + } +} diff --git a/idrocap_wa/src/Controller/AttachmentsController.php b/idrocap_wa/src/Controller/AttachmentsController.php new file mode 100644 index 0000000..4aed82a --- /dev/null +++ b/idrocap_wa/src/Controller/AttachmentsController.php @@ -0,0 +1,98 @@ +request->getQuery('withTrashed'); + $finder = !empty($withTrashed) ? 'withTrashed' : 'all'; + $attachment = $this->fetchTable('Attachments')->find($finder) + ->contain(['ContainerControllableObjects']) + ->where(['file_name' => $id]) + ->first(); + + if (!$attachment) throw new NotFoundException(__('Allegato non trovato')); + if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) throw new ForbiddenException(__('Non hai i permessi necessari per visionare l\'allegato')); + + $mimetype = $attachment->mimetype; + $file_name = $attachment->file_name; + $original_file_name = $attachment->original_file_name; + $container_co_id = $attachment->container_controllable_object_id; + $path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withAddedHeader('Content-Disposition', 'filename="' . $original_file_name . '"') + ->withCharset('UTF-8') + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } + + /** + * markAsRelevant + * + * @param Int $id + * @throws NotFoundException + * @return \Cake\Http\Response + */ + public function markAsRelevant($id = null) + { + $this->request->allowMethod(['post']); + $attachment = $this->fetchTable('Attachments')->find()->contain(['ContainerControllableObjects', 'ControllableObjects'])->where(['file_name' => $id])->first(); + + if(!$attachment) throw new NotFoundException(__('Allegato non trovato')); + if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) throw new ForbiddenException(__('Non hai i permessi necessari per visionare l\'allegato')); + + $attachment->relevant = !$attachment->relevant; + $attachment->controllable_object->id = $attachment->controllable_object->id; + $attachment->setDirty('controllable_object'); + $this->fetchTable('Attachments')->save($attachment); + $response = (object) []; + $response->result = true; + $response->relevant = $attachment->relevant; + $this->set('response', $response); + $this->viewBuilder()->setOption('serialize', 'response'); + } + + /** + * markAsDeleted + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function markAsDeleted($id = null) + { + $this->response = $this->response + ->withType('application/json') + ->withStringBody(json_encode(['result' => "markAsDeleted attachment with id '$id'. Dummy method. please do not delete it!"])); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/CapabilitiesController.php b/idrocap_wa/src/Controller/CapabilitiesController.php new file mode 100644 index 0000000..f3b97e7 --- /dev/null +++ b/idrocap_wa/src/Controller/CapabilitiesController.php @@ -0,0 +1,205 @@ +logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $capabilities = $this->Capabilities->find('withTrashed') + ->contain(['CapabilityGroups' => function ($q) { return $q->find('withTrashed'); }]); + + $capability_search = $this->request->getQuery('capability_search'); + if (!empty($capability_search)) { + $capabilities = $capabilities->where(['OR' => [ + 'Capabilities.description LIKE' => "%$capability_search%", + 'Capabilities.value LIKE' => "%$capability_search%", + 'CapabilityGroups.description LIKE' => "%$capability_search%", + ]]); + } + + $this->paginate = [ + 'sortableFields' => ['description', 'value', 'priority', 'CapabilityGroups.description'], + ]; + + $this->set('capabilities', $this->paginate($capabilities)); + $this->set('capability_search', $capability_search); + } + + /** + * hide + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function hide($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + $capability->is_configurable = false; + if ($this->Capabilities->save($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->contain(['Capabilities' => function ($q) { return $q->find('withTrashed')->where(['Capabilities.is_configurable' => 1]); }]) + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + if (count($capability_group->capabilities) == 0) { + $capability_group->is_configurable = false; + if ($this->Capabilities->CapabilityGroups->save($capability_group)) { + $errSave = false; + } + } else { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" nascosta con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante il tentativo di nascondere la Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } + + /** + * show + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function show($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + $capability->is_configurable = true; + if ($this->Capabilities->save($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + $capability_group->is_configurable = true; + if ($this->Capabilities->CapabilityGroups->save($capability_group)) { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" resa visibile con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante il tentativo di rendere visibile la Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } + + /** + * delete + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function delete($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $this->Capabilities->Permissions->addBehavior('Muffin/Trash.Trash'); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + if ($this->Capabilities->delete($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->contain(['Capabilities']) + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + if (count($capability_group->capabilities) == 0) { + if ($this->Capabilities->CapabilityGroups->delete($capability_group)) { + $errSave = false; + } + } else { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" cancellata con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante la cancellazione della Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } + + /** + * restore + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function restore($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $this->Capabilities->Permissions->addBehavior('Muffin/Trash.Trash'); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + if ($this->Capabilities->cascadingRestoreTrash($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + $capability_group->deleted = null; + if ($this->Capabilities->CapabilityGroups->save($capability_group)) { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" ripristinata con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante il ripristino della Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } +} diff --git a/idrocap_wa/src/Controller/Component/.gitkeep b/idrocap_wa/src/Controller/Component/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php b/idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php new file mode 100644 index 0000000..a6fc351 --- /dev/null +++ b/idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php @@ -0,0 +1,103 @@ +disableHydration(); + + do { + $results = $query + ->limit($chunkSize) + ->page($page) + ->all(); + + foreach ($results as $rowArray) { + + if ($extract !== null) { + if (!$wroteHeader) { + // we use the provided $headers as column names, + // otherwise we fallback to $extract array keys when they are plain string or we use "Column $key" if they are not + $headerRow = $headers ?? array_map( + function($extract_value, $extract_index) { return is_string($extract_value) ? $extract_value : "Column $extract_index"; }, + $extract, + array_keys($extract) + ); + fputcsv($out, $headerRow, ...$csvOptions); + $wroteHeader = true; + } + + $dataRow = []; + + // we use the provided $extractor to obtain the mapped values: + foreach ($extract as $column) { + if (is_callable($column)) { + $dataRow[] = $column($rowArray); + } elseif (is_string($column)) { + $dataRow[] = $rowArray[$column] ?? ''; + } else { + $dataRow[] = ''; + } + } + fputcsv($out, $dataRow, ...$csvOptions); + } else { + // there is no exctractor provided, we will take plain array keys as column names: + if (!$wroteHeader) { + fputcsv($out, array_keys($rowArray), ...$csvOptions); + $wroteHeader = true; + } + // there is no exctractor provided, we will take plain array values: + $rowValues = array_values($rowArray); + fputcsv($out, $rowValues, ...$csvOptions); + } + flush(); + } + $count = $results->count(); + $page++; + } while ($count === $chunkSize); + + fclose($out); + }); + + return $this->response + ->withType('text/csv') + ->withDownload($filename) + ->withBody($stream); + } +} diff --git a/idrocap_wa/src/Controller/ControllableObjectsController.php b/idrocap_wa/src/Controller/ControllableObjectsController.php new file mode 100644 index 0000000..708925d --- /dev/null +++ b/idrocap_wa/src/Controller/ControllableObjectsController.php @@ -0,0 +1,56 @@ +ControllableObjects->Attachments + ->find() + ->contain(['ControllableObjects' => ['Creator', 'Modifier', 'Locations']]) + ->where(['Attachments.container_controllable_object_id' => $co_id]); + + if(!empty($this->request->getQuery('tags'))) { + $tags = explode(',', $this->request->getQuery('tags')); + $attachments = $attachments + ->matching('Tags') + ->where(['Tags.code IN' => $tags]); + } + + $showPrivateColumn = $attachments->all()->filter(function ($attachment) { return $attachment->private == 1; })->count() > 0; + + if (!$this->logged_user->canHandleAttachmentsForControllableObject($this->ControllableObjects->get($co_id))) { + $attachments = $attachments->where(['Attachments.id < 0']); + } + + $this->paginate = [ + 'sortableFields' => ['Attachments.private', 'Attachments.original_file_name', 'Locations.description', 'Attachments.relevant', 'Attachments.original_file_size', 'Attachments.mimetype', 'Attachments.upload_date', 'Creator.surname'], + 'limit' => 10, + 'order' => [ + 'Attachments.upload_date' => 'DESC' + ], + ]; + + if ($this->request->getQuery('removecurrentfiles') !== null) { + $this->set('removecurrentfiles', $this->request->getQuery('removecurrentfiles')); + } + + $this->viewBuilder()->setLayout('ajax'); + $this->set('numberOfAttachments', $attachments->count()); + $this->set('attachments', $this->paginate($attachments)); + $this->set('showPrivateColumn', $showPrivateColumn); + } +} diff --git a/idrocap_wa/src/Controller/DashboardController.php b/idrocap_wa/src/Controller/DashboardController.php new file mode 100644 index 0000000..733b662 --- /dev/null +++ b/idrocap_wa/src/Controller/DashboardController.php @@ -0,0 +1,35 @@ +Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canViewContactsForActor($actor)) throw new ForbiddenException(__('Non hai i permessi per visualizzare i recapiti per {0}', $actor_type_description)); + + $mobile_phones = $this->Deliveries->MobilePhones->find() + ->contain(['MobilePhoneDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'mobile_phone')) { + $mobile_phones = $mobile_phones->map(function ($mobile_phone) { + $mobile_phone->value = "**************"; + return $mobile_phone; + }); + } + + $faxes = $this->Deliveries->Faxes->find() + ->contain(['FaxDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'fax')) { + $faxes = $faxes->map(function ($fax) { + $fax->value = "**************"; + return $fax; + }); + } + + $emails = $this->Deliveries->Emails->find() + ->contain(['EmailDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'email')) { + $emails = $emails->map(function ($email) { + $email->value = "**************"; + return $email; + }); + } + + $phones = $this->Deliveries->Phones->find() + ->contain(['PhoneDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'phone')) { + $phones = $phones->map(function ($phone) { + $phone->value = "**************"; + return $phone; + }); + } + + $telegram_chats = $this->Deliveries->TelegramChats->find() + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'telegram_chat')) { + $telegram_chats = $telegram_chats->map(function ($telegram_chat) { + $telegram_chat->value = "**************"; + return $telegram_chat; + }); + } + + $pecs = $this->Deliveries->Pecs->find() + ->contain(['PecDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'pec')) { + $pecs = $pecs->map(function ($pec) { + $pec->value = "**************"; + return $pec; + }); + } + + $can_add_mobile_phone = $this->logged_user->canAddContactsForActor($actor, 'mobile_phone'); + $can_edit_mobile_phone = $this->logged_user->canEditContactsForActor($actor, 'mobile_phone'); + $can_delete_mobile_phone = $this->logged_user->canDeleteContactsForActor($actor, 'mobile_phone'); + $can_add_fax = $this->logged_user->canAddContactsForActor($actor, 'fax'); + $can_edit_fax = $this->logged_user->canEditContactsForActor($actor, 'fax'); + $can_delete_fax = $this->logged_user->canDeleteContactsForActor($actor, 'fax'); + $can_add_email = $this->logged_user->canAddContactsForActor($actor, 'email'); + $can_edit_email = $this->logged_user->canEditContactsForActor($actor, 'email'); + $can_delete_email = $this->logged_user->canDeleteContactsForActor($actor, 'email'); + $can_add_phone = $this->logged_user->canAddContactsForActor($actor, 'phone'); + $can_edit_phone = $this->logged_user->canEditContactsForActor($actor, 'phone'); + $can_delete_phone = $this->logged_user->canDeleteContactsForActor($actor, 'phone'); + $can_add_telegram_chat = $this->logged_user->canAddContactsForActor($actor, 'telegram_chat'); + $can_edit_telegram_chat = $this->logged_user->canEditContactsForActor($actor, 'telegram_chat'); + $can_delete_telegram_chat = $this->logged_user->canDeleteContactsForActor($actor, 'telegram_chat'); + $can_add_pec = $this->logged_user->canAddContactsForActor($actor, 'pec'); + $can_edit_pec = $this->logged_user->canEditContactsForActor($actor, 'pec'); + $can_delete_pec = $this->logged_user->canDeleteContactsForActor($actor, 'pec'); + + $this->set(compact('actor', 'mobile_phones', 'faxes', 'emails', 'phones', 'telegram_chats', 'pecs', 'can_add_mobile_phone', 'can_edit_mobile_phone', 'can_delete_mobile_phone', 'can_add_fax', 'can_edit_fax', 'can_delete_fax', 'can_add_email', 'can_edit_email', 'can_delete_email', 'can_add_phone', 'can_edit_phone', 'can_delete_phone', 'can_add_telegram_chat', 'can_edit_telegram_chat', 'can_delete_telegram_chat', 'can_add_pec', 'can_edit_pec', 'can_delete_pec')); + } + + /** + * delete + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $delivery = $this->Deliveries->get($id, contain: ['DeliveryTypes', 'MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]); + + $actor = $this->Deliveries->Actors->get($delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canDeleteContactsForActor($actor, $delivery->delivery_type->description)) throw new ForbiddenException(__('Non hai i permessi per eliminare i recapiti di questo tipo per {0}', $actor_type_description)); + + $contact_value = ""; + + switch ($delivery->delivery_type_id) { + case 1: + $contact_value = __('Cellulare ({0}): {1}', $delivery->mobile_phone->mobile_phone_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->mobile_phone->value : "**************"); + break; + case 2: + $contact_value = __('Fax ({0}): {1}', $delivery->fax->fax_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->fax->value: "**************"); + break; + case 3: + $contact_value = __('Email ({0}): {1}', $delivery->email->email_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->email->value: "**************"); + break; + case 4: + $contact_value = __('Telefono ({0}): {1}', $delivery->phone->phone_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->phone->value: "**************"); + break; + case 5: + $contact_value = __('Telegram Chat ID: {0}', $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->telegram_chat->value: "**************"); + break; + case 6: + $contact_value = __('PEC ({0}): {1}', $delivery->pec->pec_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->pec->value: "**************"); + break; + default: + $contact_value = ""; + break; + } + + if ($this->Deliveries->delete($delivery)) { + $this->Flash->success(__('Il recapito "{0}" è stato cancellato con successo', $contact_value)); + } else { + $this->Flash->error(__('Errore durante la cancellazione del recapito {0}. Riprovare di nuovo.', $contact_value)); + } + + return $this->redirect(['action' => 'index', $delivery->actor_id]); + } +} diff --git a/idrocap_wa/src/Controller/DistrictsController.php b/idrocap_wa/src/Controller/DistrictsController.php new file mode 100644 index 0000000..61e2f39 --- /dev/null +++ b/idrocap_wa/src/Controller/DistrictsController.php @@ -0,0 +1,66 @@ +viewBuilder()->setClassName('Json'); + $conditions = []; + $provinceCode = $this->request->getQuery(ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::PROVINCE_CODE)); + $term = $this->request->getQuery("term"); + $codeReg = ProvinceDistrictFieldHelper::getCodeRegByRegion(Regions::SICILY); + $regCodField = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::REGION_CODE); + $provCodeField = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::PROVINCE_CODE); + $queryDistrictFieldName = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::DISTRICT_FIELD_NAME); + + if($codeReg) { + $conditions[$regCodField] = $codeReg; + } + + if (isset($provinceCode)) { + $conditions[$provCodeField] = $provinceCode; + } + + $query = $this->Districts->find(); + + if ($term) { + $query->where(function ($exp) use ($term, $queryDistrictFieldName) { + return $exp->like($queryDistrictFieldName, "%$term%"); + }); + } + + if (!empty($conditions)) { + $query->where($conditions); + } + + $district_field = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::DISTRICT_FIELD_NAME); + $districts = $query->find('list', keyField: $district_field, valueField: $district_field)->toArray(); + + $this->set(compact('districts')); + $this->viewBuilder()->setOption('serialize', ['districts'])->setOption('jsonOptions', JSON_FORCE_OBJECT); + } +} diff --git a/idrocap_wa/src/Controller/EmailsController.php b/idrocap_wa/src/Controller/EmailsController.php new file mode 100644 index 0000000..8c5f63b --- /dev/null +++ b/idrocap_wa/src/Controller/EmailsController.php @@ -0,0 +1,78 @@ +Emails->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'email')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $email = $this->Emails->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 3, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $email = $this->Emails->patchEntity($email, $this->request->getData()); + if ($this->Emails->save($email)) { + $this->Flash->success(__('L\'Email è stata aggiunta con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta dell\'Email')); + } + $emailDescriptions = $this->Emails->EmailDescriptions->find('list'); + $this->set(compact('actor', 'email', 'emailDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $email = $this->Emails->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Emails->Deliveries->Actors->get($email->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'email')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $email = $this->Emails->patchEntity($email, $this->request->getData()); + if ($this->Emails->save($email)) { + $this->Flash->success(__('L\'Email è stata modificata con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $email->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica dell\'Email. Riprovare di nuovo')); + } + $emailDescriptions = $this->Emails->EmailDescriptions->find('list'); + $this->set(compact('actor', 'email', 'emailDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/ErrorController.php b/idrocap_wa/src/Controller/ErrorController.php new file mode 100644 index 0000000..d0fd7eb --- /dev/null +++ b/idrocap_wa/src/Controller/ErrorController.php @@ -0,0 +1,70 @@ +viewBuilder()->setTemplatePath('Error'); + } + + /** + * afterFilter callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function afterFilter(EventInterface $event) + { + } +} diff --git a/idrocap_wa/src/Controller/FaxesController.php b/idrocap_wa/src/Controller/FaxesController.php new file mode 100644 index 0000000..89bc206 --- /dev/null +++ b/idrocap_wa/src/Controller/FaxesController.php @@ -0,0 +1,78 @@ +Faxes->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'fax')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $fax = $this->Faxes->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 2, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $fax = $this->Faxes->patchEntity($fax, $this->request->getData()); + if ($this->Faxes->save($fax)) { + $this->Flash->success(__('Il Fax è stato aggiunto con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta del Fax')); + } + $faxDescriptions = $this->Faxes->FaxDescriptions->find('list'); + $this->set(compact('actor', 'fax', 'faxDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $fax = $this->Faxes->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Faxes->Deliveries->Actors->get($fax->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'fax')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $fax = $this->Faxes->patchEntity($fax, $this->request->getData()); + if ($this->Faxes->save($fax)) { + $this->Flash->success(__('Il Fax è stato modificato con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $fax->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica del Fax. Riprovare di nuovo')); + } + $faxDescriptions = $this->Faxes->FaxDescriptions->find('list'); + $this->set(compact('actor', 'fax', 'faxDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/FiltersController.php b/idrocap_wa/src/Controller/FiltersController.php new file mode 100644 index 0000000..ad09547 --- /dev/null +++ b/idrocap_wa/src/Controller/FiltersController.php @@ -0,0 +1,25 @@ +set('filter_id', $filter_id); + $this->viewBuilder()->setLayout('ajax'); + } +} diff --git a/idrocap_wa/src/Controller/GroupsController.php b/idrocap_wa/src/Controller/GroupsController.php new file mode 100644 index 0000000..d7632e5 --- /dev/null +++ b/idrocap_wa/src/Controller/GroupsController.php @@ -0,0 +1,236 @@ +logged_user->hasCapability('configuration.groups.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $groups = $this->Groups->find() + ->contain(['Actors', 'ChildGroups']); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $groups = $groups + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('configuration.groups.edit'); + $row->can_delete = $this->logged_user->hasCapability('configuration.groups.delete'); + $row->child_groups_csv = collection($row->child_groups)->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group->description : ($csv . ', ' . $child_group->description); }, ''); + return $row; + }); + }); + } + + $this->paginate = [ + 'sortableFields' => ['description', 'is_default'], + ]; + + $this->set('groups', $this->getRequest()->is(['json', 'xml', 'csv']) ? $groups : $this->paginate($groups)); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('configuration.groups.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Descrizione'), + __('Profilo Default'), + __('Profili Associati'), + ]; + $extract = [ + 'description', + function (array $row) { + return $row['is_default'] ? __('SI') : __('NO'); + }, + function (array $row) { + return collection($row['child_groups'])->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group['description'] : ($csv . ', ' . $child_group['description']); }, ''); + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("profiles_$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'groups'); + } + + /** + * view + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->get($id, contain: ['Actors', 'ChildGroups']); + + $group->can_handle_capabilities = $this->logged_user->hasCapability('configuration.groups.capabilities'); + $group->can_edit = $this->logged_user->hasCapability('configuration.groups.edit'); + $group->can_delete = $this->logged_user->hasCapability('configuration.groups.delete'); + $group->child_groups_csv = collection($group->child_groups)->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group->description : ($csv . ', ' . $child_group->description); }, ''); + + $this->set(compact('group')); + $this->viewBuilder()->setOption('serialize', 'group'); + } + + /** + * add + * + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability('configuration.groups.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->newEmptyEntity(); + if ($this->request->is('post')) { + $group = $this->Groups->patchEntity($group, $this->request->getData()); + if ($this->Groups->save($group)) { + $this->Flash->success(__('Profilo Utente creato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la creazione del Profilo Utente')); + } + $child_groups = $this->fetchTable('Groups')->find('list')->contain(['Actors'])->order(['Groups.description' => 'ASC']); + $this->set(compact('group')); + $this->set(compact('child_groups')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.edit')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->get($id, contain: ['Actors', 'ChildGroups']); + if ($this->request->is(['patch', 'post', 'put'])) { + $group = $this->Groups->patchEntity($group, $this->request->getData()); + if ($this->Groups->save($group)) { + $this->Flash->success(__('Profilo Utente "{0}" modificato con successo.', $group->description)); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la modifica del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); + } + $child_groups = $this->fetchTable('Groups')->find('list')->contain(['Actors'])->order(['Groups.description' => 'ASC']); + $this->set(compact('group')); + $this->set(compact('child_groups')); + } + + /** + * delete + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.delete')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $group = $this->Groups->get($id, contain: ['Actors']); + + if ($this->Groups->Actors->delete($group->actor)) { + $this->Flash->success(__('Il Profilo Utente "{0}" è stato cancellato con successo', $group->description)); + } else { + $errors = $group->actor->getErrors(); + if (isset($errors['is_editable']['checkGroupIsEditable'])) { + $errorMessage = $errors['is_editable']['checkGroupIsEditable']; + $this->Flash->error($errorMessage); + } else { + $this->Flash->error(__('Errore durante la cancellazione del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); + } + } + + return $this->redirect(['action' => 'index']); + } + + /** + * handleCapabilities + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function handleCapabilities($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.capabilities')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->get($id, contain: ['Actors']); + + $group_capability_ids = $this->Groups->Capabilities->find() + ->select(['id']) + ->matching('Groups') + ->where(['Groups.id' => $id]); + + if (!$this->logged_user->sys_admin) { + $group_capability_ids = $group_capability_ids + ->where(['Capabilities.is_configurable' => 1]); + } + + $group_capability_ids = $group_capability_ids + ->distinct() + ->all() + ->extract('id') + ->toArray(); + + if ($this->request->is(['patch', 'post', 'put'])) { + $group = $this->Groups->patchEntity($group, $this->request->getData(), ['group_id' => $group->id]); + if ($this->Groups->save($group)) { + $this->Flash->success(__('Profilo Utente "{0}" modificato con successo.', $group->description)); + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la modifica del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); + } + + $capability_groups = $this->Groups->Capabilities->CapabilityGroups->find() + ->contain(['Capabilities' => function ($q) { + if (!$this->logged_user->sys_admin) { + $q->where(['Capabilities.is_configurable' => 1]); + } + return $q->order(['Capabilities.capability_group_id' => 'ASC', 'Capabilities.priority_group_id' => 'ASC', 'Capabilities.priority' => 'ASC', 'Capabilities.description']); + }]) + ->order(['CapabilityGroups.description' => 'ASC']); + + $this->set(compact('group', 'group_capability_ids', 'capability_groups')); + $this->viewBuilder()->setOption('serialize', 'group'); + } +} diff --git a/idrocap_wa/src/Controller/MapsController.php b/idrocap_wa/src/Controller/MapsController.php new file mode 100644 index 0000000..c2987da --- /dev/null +++ b/idrocap_wa/src/Controller/MapsController.php @@ -0,0 +1,187 @@ +'], ['%20', '%3E'], $query_parameters); + $url .= $query_parameters; + $http = new Client(); + $response = $http->get($url, [], [ + 'auth' => ['username' => Configure::read('App.geoserverUsername'), 'password' => Configure::read('App.geoserverPassword')] + ]); + return $response->getStringBody(); + } + + /** + * get_location_attributes + * + * @param String $lat + * @param String $lon + * @return ?Array + */ + private function get_location_attributes(String $lat, String $lon): ?Array { + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; + $location = $this->fetchTable('Locations')->newEntity([ + 'feature_collection' => $feature_collection, + ]); + $lar = new LocationAttributesRetriever($location); + $lar_result = $lar->retrieve()[0] ?? null; + return $lar_result; + } + + /** + * get_matching_geo_resources + * + * @param String $lat + * @param String $lon + * @return ?Array + */ + private function get_matching_geo_resources(String $lat, String $lon): ?Array { + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; + $matching_geo_resources = []; + // inizializziamo l'array $mapped_fields con un array associativo con KEY id del campo e VALUE '': + $mapped_fields = collection($this->geo_resources)->reduce(function ($acc, $geo_resource) { + return array_merge($acc, array_fill_keys(array_values($geo_resource['attributes_fields']), '')); + }, []); + + foreach ($this->geo_resources as $geo_resource) { + if (isset($geo_resource['external']) && is_bool($geo_resource['external']) && $geo_resource['external']) { + $grar = new ExtGeoResourceAttributesRetriever($geo_resource['url'], $geo_resource['lon_parameter_name'], $geo_resource['lat_parameter_name']); + $grar_result = $grar->retrieve($lon, $lat); + if (isset($grar_result)) { + // scremiamo il risultato proveniente dal servizio esterno considerando solo gli attributi che ci interessano: + $grar_result = array_intersect_key($grar_result, $geo_resource['attributes_fields']); + $matching_geo_resources[$geo_resource['url']] = $grar_result; + foreach ($grar_result as $attribute_name => $attribute_value) { + $mapped_fields[$geo_resource['attributes_fields'][$attribute_name]] = $attribute_value; + } + } + } else { + $grar = new IntGeoResourceAttributesRetriever($geo_resource['table_name'], $geo_resource['geometry_name'], array_keys($geo_resource['attributes_fields'])); + $grar_result = $grar->retrieve($feature_collection)[0] ?? null; + if (isset($grar_result)) { + $matching_geo_resources[$geo_resource['table_name']] = $grar_result; + foreach ($grar_result as $attribute_name => $attribute_value) { + $mapped_fields[$geo_resource['attributes_fields'][$attribute_name]] = $attribute_value; + } + } + } + } + return ['matching_geo_resources' => $matching_geo_resources, 'mapped_fields' => $mapped_fields]; + } + + /** + * map_geocoding_result_content + * + * @param Array $content + * @return Array + */ + private function map_geocoding_result_content(Array $content): Array { + $array_content = explode(", ", $content['display_name'] ?? ''); + $index_cursor = count($array_content) - 1; + if ($index_cursor > 0) $nation = $array_content[$index_cursor--]; + if ($index_cursor > 0) $cap = (Int)$array_content[$index_cursor] > 0 ? $array_content[$index_cursor--] : ''; + if ($index_cursor > 0) $region = $array_content[$index_cursor--]; + if ($index_cursor > 0) $province = $array_content[$index_cursor--]; + if ($index_cursor > 0) $district = $array_content[$index_cursor--]; + $address = $content['namedetails']['name'] ?? ''; + $description = $content['display_name'] ?? ''; + $lat = $content['lat'] ?? ''; + $lon = $content['lon'] ?? ''; + return ['nation' => $nation ?? '', 'cap' => $cap ?? '', 'region' => $region ?? '', 'province' => $province ?? '', 'district' => $district ?? '', 'address' => $address, 'lat' => $lat, 'lon' => $lon, 'description' => $description]; + } + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index () { + if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); + } + + /** + * getWfs + * + * @return Response + */ + public function getWfs(): Response { + if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); + $response = $this->geoserver_proxy($this->request->getUri()->getQuery()); + return $this->getResponse()->withStringBody($response)->withType("application/json"); + } + + /** + * geocode + * + * @throws BadRequestException + * @throws NotFoundException + * @return Response + */ + public function geocode(): Response { + if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); + // geo_resources, se presente, contiene le info per mappare campi aggiuntivi con attributi di + // una o + geo-risorse in base a dove il punto specificato ricade: + $geo_resources = json_decode($this->request->getQuery('geo_resources') ?? '', true); + if ($geo_resources !== null && is_array($geo_resources) && count($geo_resources) > 0) $this->geo_resources = $geo_resources; + + if ($this->request->getQuery('address') === null) throw new BadRequestException('geocode error: invalid address'); + + $separator = null; + + if (count(collection(explode(" ", $this->request->getQuery('address')))->filter(function ($part) { return is_numeric(trim($part)); })->toArray()) === 2) { + $separator = " "; + } + + if (count(collection(explode(",", $this->request->getQuery('address')))->filter(function ($part) { return is_numeric(trim($part)); })->toArray()) === 2) { + $separator = ","; + } + + if ($separator !== null) { + $address_parts = explode($separator, $this->request->getQuery('address')); + $lat = $address_parts[0] > $address_parts[1] ? $address_parts[0] : $address_parts[1]; + $lon = $address_parts[0] > $address_parts[1] ? $address_parts[1] : $address_parts[0]; + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; + if (!GeoValidation::isValidGeometry(json_decode($feature_collection))) throw new BadRequestException('invalid coordinates or out of boundary!'); + $reverse_geocoding = Geocoding::performGeocoding('reverse', ['format' => 'json', 'namedetails' => '1', 'lat' => $lat, 'lon' => $lon]); + if (!empty($reverse_geocoding['contents'])) { + $mapped_geocoding_result_content = $this->map_geocoding_result_content($reverse_geocoding['contents']); + } + $lar_result = $this->get_location_attributes($lat, $lon); + $content = ['geo_resources' => $this->get_matching_geo_resources($lat, $lon), 'nation' => $mapped_geocoding_result_content['nation'] ?? '', 'cap' => $mapped_geocoding_result_content['cap'] ?? '', 'region' => $lar_result['region'] ?? $mapped_geocoding_result_content['region'] ?? '', 'province' => $lar_result['county_name'] ?? $mapped_geocoding_result_content['province'] ?? '', 'district_code' => $lar_result['district_code'] ?? '', 'district' => $lar_result['district_name'] ?? $mapped_geocoding_result_content['district'] ?? '', 'address' => $mapped_geocoding_result_content['address'] ?? '', 'lat' => $lat, 'lon' => $lon, 'description' => !empty($mapped_geocoding_result_content['description']) ? $mapped_geocoding_result_content['description'] : __('Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}', $lat, $lon)]; + return $this->getResponse()->withStringBody(json_encode($content))->withType("application/json"); + } + + $geocoding = Geocoding::performGeocoding('search', ['format' => 'json', 'namedetails' => '1', 'q' => $this->request->getQuery('address')]); + if (empty($geocoding['contents'])) throw new NotFoundException('geocode error: no contents'); + return $this->getResponse()->withStringBody(json_encode($geocoding['contents']))->withType("application/json"); + } +} diff --git a/idrocap_wa/src/Controller/MobilePhonesController.php b/idrocap_wa/src/Controller/MobilePhonesController.php new file mode 100644 index 0000000..b1fca0f --- /dev/null +++ b/idrocap_wa/src/Controller/MobilePhonesController.php @@ -0,0 +1,79 @@ +MobilePhones->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'mobile_phone')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $mobilePhone = $this->MobilePhones->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 1, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $mobilePhone = $this->MobilePhones->patchEntity($mobilePhone, $this->request->getData()); + if ($this->MobilePhones->save($mobilePhone)) { + $this->Flash->success(__('Il Cellulare è stato aggiunto con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta del Cellulare')); + } + $mobilePhoneDescriptions = $this->MobilePhones->MobilePhoneDescriptions->find('list'); + $this->set(compact('actor', 'mobilePhone', 'mobilePhoneDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $mobilePhone = $this->MobilePhones->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->MobilePhones->Deliveries->Actors->get($mobilePhone->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'mobile_phone')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $mobilePhone = $this->MobilePhones->patchEntity($mobilePhone, $this->request->getData()); + if ($this->MobilePhones->save($mobilePhone)) { + $this->Flash->success(__('Il Cellulare è stato modificato con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $mobilePhone->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica del Cellulare. Riprovare di nuovo')); + } + $mobilePhoneDescriptions = $this->MobilePhones->MobilePhoneDescriptions->find('list'); + $this->set(compact('actor', 'mobilePhone', 'mobilePhoneDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/NotificationsController.php b/idrocap_wa/src/Controller/NotificationsController.php new file mode 100644 index 0000000..800a842 --- /dev/null +++ b/idrocap_wa/src/Controller/NotificationsController.php @@ -0,0 +1,97 @@ +fetchTable('Notifications') + ->find() + ->contain('NotificationTypes') + ->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) + ->order(['Notifications.created' => 'DESC']) + ->all() + ->reduce(function ($acc, $user_notification) { + $notification_info = json_decode($user_notification->info); + $body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; + $icon = $user_notification->notification_type->icon ?? 'bell'; + $time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); + $acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; + return $acc; + }, []); + } + + /** + * readAll + * + * @return \Cake\Http\Response + */ + public function readAll() + { + $this->fetchTable('Notifications')->updateAll(['read_by_user' => new DateTime()], ['user_id' => $this->logged_user->id, 'read_by_user IS NULL']); + $user_notifications = $this->getUserNotifications(); + $this->set('user_notifications', $user_notifications); + $this->viewBuilder()->setOption('serialize', 'user_notifications')->setLayout('ajax'); + } + + /** + * testAll + * + * @return \Cake\Http\Response + */ + public function testAll() + { + $this->request->allowMethod(['post']); + $this->sendNotifications(null, 'test_all', []); + return $this->redirect('/'); + } + + /** + * view + * + * @todo recuperare la specializzazione del CO e fare redirect alla view dell'oggetto specifico! + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id) + { + $notification = $this->fetchTable('Notifications')->get($id); + $notification->read_by_user = new DateTime(); + + if (!$this->fetchTable('Notifications')->save($notification)) { + $this->Flash->error(__('Errore durante la cancellazione della notifica')); + } + + $notification_info = json_decode($notification->info); + $link = !empty($notification_info->link) ? $notification_info->link : '/'; + return $this->redirect($link); + } + + public function index() + { + $user_notifications = $this->getUserNotifications(); + $this->set('user_notifications', $user_notifications); + $this->viewBuilder()->setOption('serialize', 'user_notifications')->setLayout('ajax'); + } +} diff --git a/idrocap_wa/src/Controller/OrganisationsController.php b/idrocap_wa/src/Controller/OrganisationsController.php new file mode 100644 index 0000000..5b156b9 --- /dev/null +++ b/idrocap_wa/src/Controller/OrganisationsController.php @@ -0,0 +1,204 @@ +logged_user->hasCapability('configuration.organisations.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisations = $this->Organisations->find() + ->contain(['OrganisationTypes', 'Actors']); + + $this->set('total_organisations', $organisations->count()); + // applichiamo gli eventuali filtri presenti: + $organisations = $this->applyFilters($organisations); + $this->set('filtered_organisations', $organisations->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $organisations = $organisations + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->organisation_id == $row->id || $this->logged_user->hasCapability('configuration.organisations.edit'); + $row->can_delete = $this->logged_user->organisation_id == $row->id || $this->logged_user->hasCapability('configuration.organisations.delete'); + return $row; + }); + }); + } + + $this->paginate = [ + 'sortableFields' => ['Actors.description', 'acronym', 'OrganisationTypes.description', 'address', 'district', 'cap', 'province'], + ]; + + $this->set('organisations', $this->getRequest()->is(['json', 'xml', 'csv']) ? $organisations : $this->paginate($organisations)); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('configuration.organisations.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Descrizione'), + __('Acronimo'), + __('Tipologia'), + __('Indirizzo'), + __('Comune'), + __('CAP'), + __('Provincia'), + __('Recapiti'), + ]; + $extract = [ + function (array $row) { + return $row['actor']['description']; + }, + 'acronym', + function (array $row) { + return $row['organisation_type']['description']; + }, + 'address', + 'district', + 'cap', + 'province', + function (array $row) { + return $row['actor']['contacts']; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("organisations_$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'organisations'); + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id = null) + { + if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisation = $this->Organisations->get($id, contain: ['ControllableObjectInterfaces', 'OrganisationTypes', 'Actors']); + + $organisation->can_handle_contacts = $this->logged_user->canViewContactsForActor($this->Organisations->Actors->get($organisation->actor_id, contain: ['Organisations'])); + $organisation->can_edit = $this->logged_user->organisation_id == $id || $this->logged_user->hasCapability('configuration.organisations.edit'); + $organisation->can_delete = $this->logged_user->organisation_id == $id || $this->logged_user->hasCapability('configuration.organisations.delete'); + + $organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); + $this->set(compact('organisation', 'organisationTypes')); + } + + /** + * add + * + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability('configuration.organisations.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisation = $this->Organisations->newEmptyEntity(); + if ($this->request->is('post')) { + $organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); + if ($this->Organisations->save($organisation)) { + $this->Flash->success(__('Organizzazione creata con successo.')); + + return $this->redirect(['action' => 'index']); + } + $errorMessage = $organisation->getError('attachment')[0] ?? ''; + $this->Flash->error(__('Errore durante la creazione dell\'organizzazione. ' . $errorMessage)); + } + $organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); + $this->set(compact('organisation', 'organisationTypes')); + } + + /** + * edit + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.edit')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisation = $this->Organisations->get($id, contain: ['Actors', 'ControllableObjectInterfaces', 'OrganisationTypes']); + if ($this->request->is(['patch', 'post', 'put'])) { + $organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); + if ($this->Organisations->save($organisation)) { + $this->Flash->success(__('Organizzazione "{0}" modificata con successo.', $organisation->actor->description)); + + return $this->redirect(['action' => 'index']); + } + $errMessage = $organisation->getError('attachment')[0] ?? ''; + $this->Flash->error(__('Errore durante la modifica dell\'organizzazione "{0}". Riprovare di nuovo. ', $organisation->actor->description) . $errMessage); + } + $organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); + $this->set(compact('organisation', 'organisationTypes')); + } + + /** + * delete + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.delete')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $organisation = $this->Organisations->get($id, contain: ['Actors']); + + // controlliamo se il type è cittadini e preveniamo la possibilità di delete. + if($organisation->organisation_type_id === 7) { + $this->Flash->error(__('Impossibile eliminare l\'organizzazione "{0}".', $organisation->actor->description)); + return $this->redirect(['action' => 'index']); + } + + $are_there_users_in_this_org = $this->fetchTable('Users')->find()->where(['Users.organisation_id' => $id])->count(); + if ($are_there_users_in_this_org > 0) { + $this->Flash->error(__('Impossibile eliminare l\'organizzazione "{0}". Ci sono {1} utenti collegati ad essa.', $organisation->actor->description, $are_there_users_in_this_org)); + return $this->redirect(['action' => 'index']); + } + + if ($this->Organisations->Actors->delete($organisation->actor)) { + $this->Flash->success(__('L\'organizzazione "{0}" è stata cancellata con successo', $organisation->actor->description)); + } else { + $this->Flash->error(__('Errore durante la cancellazione dell\'organizzazione "{0}". Riprovare di nuovo.', $organisation->actor->description)); + } + + return $this->redirect(['action' => 'index']); + } +} diff --git a/idrocap_wa/src/Controller/PecsController.php b/idrocap_wa/src/Controller/PecsController.php new file mode 100644 index 0000000..d3bc5f5 --- /dev/null +++ b/idrocap_wa/src/Controller/PecsController.php @@ -0,0 +1,78 @@ +Pecs->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'pec')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $pec = $this->Pecs->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 6, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $pec = $this->Pecs->patchEntity($pec, $this->request->getData()); + if ($this->Pecs->save($pec)) { + $this->Flash->success(__('La PEC è stata aggiunta con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta della PEC')); + } + $pecDescriptions = $this->Pecs->PecDescriptions->find('list'); + $this->set(compact('actor', 'pec', 'pecDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $pec = $this->Pecs->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Pecs->Deliveries->Actors->get($pec->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'pec')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $pec = $this->Pecs->patchEntity($pec, $this->request->getData()); + if ($this->Pecs->save($pec)) { + $this->Flash->success(__('La PEC è stata modificata con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $pec->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica della PEC. Riprovare di nuovo')); + } + $pecDescriptions = $this->Pecs->PecDescriptions->find('list'); + $this->set(compact('actor', 'pec', 'pecDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/PhonesController.php b/idrocap_wa/src/Controller/PhonesController.php new file mode 100644 index 0000000..add984c --- /dev/null +++ b/idrocap_wa/src/Controller/PhonesController.php @@ -0,0 +1,78 @@ +Phones->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'phone')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $phone = $this->Phones->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 4, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $phone = $this->Phones->patchEntity($phone, $this->request->getData()); + if ($this->Phones->save($phone)) { + $this->Flash->success(__('Il Telefono è stato aggiunto con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta del Telefono')); + } + $phoneDescriptions = $this->Phones->PhoneDescriptions->find('list'); + $this->set(compact('actor', 'phone', 'phoneDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $phone = $this->Phones->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Phones->Deliveries->Actors->get($phone->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'phone')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $phone = $this->Phones->patchEntity($phone, $this->request->getData()); + if ($this->Phones->save($phone)) { + $this->Flash->success(__('Il Telefono è stato modificato con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $phone->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica del Telefono. Riprovare di nuovo')); + } + $phoneDescriptions = $this->Phones->PhoneDescriptions->find('list'); + $this->set(compact('actor', 'phone', 'phoneDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/PrivacyController.php b/idrocap_wa/src/Controller/PrivacyController.php new file mode 100644 index 0000000..6ff81f6 --- /dev/null +++ b/idrocap_wa/src/Controller/PrivacyController.php @@ -0,0 +1,174 @@ +Authentication->allowUnauthenticated(['view_public']); + } + + /** + * Index method + * + * @return \Cake\Http\Response|null|void Renders view + */ + public function view_public() + { + $privacy = $this->Privacy->findPrivacy(); + $this->viewBuilder()->setLayout('view_public'); + $this->set(compact('privacy')); + } + + /** + * View method + * + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view() + { + $breadcrumbs = $this->retrieveBreadcrumbs('view'); + $privacy = $this->Privacy->findPrivacy(); + $this->set(compact('privacy', 'breadcrumbs')); + } + + /** + * Edit method + * + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit() + { + if (!$this->logged_user->hasCapability(['configuration.privacy.edit'])) { + throw new ForbiddenException(__('Non hai i permessi necessari')); + } + + $breadcrumbs = $this->retrieveBreadcrumbs('edit'); + $privacy = $this->Privacy->findPrivacy(); + if ($this->request->is(['patch', 'post', 'put'])) { + $privacy = $this->Privacy->patchEntity($privacy, $this->request->getData()); + try { + $connection = ConnectionManager::get('default'); + $connection->begin(); + if ($this->Privacy->save($privacy)) { + $this->Privacy->PrivacyUsers->deleteAll(['privacy_id' => $privacy->id]); + $connection->commit(); + $this->Flash->success(__('La privacy è stata salvata con successo.')); + } else { + $connection->rollback(); + $this->Flash->error(__('La privacy non è stata salvata. Riprova, per favore.')); + } + } catch(Exception $e) { + $connection->rollback(); + $this->Flash->error(__('Errore. La privacy non è stata salvata.')); + } + } + $this->set(compact('privacy', 'breadcrumbs')); + } + + public function accept_privacy() + { + $hasConsent = $this->Privacy->PrivacyUsers->hasConsent($this->logged_user->id); + if ($hasConsent) { + $this->Flash->error(__('Hai già accettato la privacy.')); + return $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); + } + $breadcrumbs = $this->retrieveBreadcrumbs('accept_privacy'); + $privacy = $this->Privacy->findPrivacy(); + if (!$privacy) { + $this->Flash->error(__('La privacy non è disponibile.')); + return $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); + } + + if ($this->request->is(['post', 'put', 'patch'])) { + if ($this->Privacy->PrivacyUsers->saveConsent($this->logged_user->id, $privacy->id)) { + $this->Flash->success(__('La privacy è stata accettata con successo.')); + $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); + } else { + $this->Flash->error(__('Errore. La privacy non è stata accettata.')); + } + } + $this->set(compact('privacy', 'breadcrumbs')); + } + + private function retrieveBreadcrumbs(string $action): array + { + $breadcrumbs = [ + 'edit' => [ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Privacy'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Modifica privacy'), + 'icon' => 'fa fa-pencil-alt', + ], + ], + 'view' => + [ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Privacy'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Visualizza privacy'), + 'icon' => 'fa fa-info', + ], + ], + 'accept_privacy' => [ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Privacy'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Visualizzazione privacy'), + 'icon' => 'fa fa-info', + ], + ] + ]; + + return $breadcrumbs[$action] ?? []; + } +} diff --git a/idrocap_wa/src/Controller/TagsController.php b/idrocap_wa/src/Controller/TagsController.php new file mode 100644 index 0000000..17905dc --- /dev/null +++ b/idrocap_wa/src/Controller/TagsController.php @@ -0,0 +1,91 @@ +logged_user->hasCapability(['configuration.tags.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tags = $this->Tags->find()->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('configuration.tags.edit'); + $row->can_view = $this->logged_user->hasCapability('configuration.tags.disable'); + return $row; + }); + }); + $tags = $this->paginate($tags); + $this->set(compact('tags')); + } + + /** + * View method + * + * @param string|null $id Tag id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability(['configuration.tags.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tag = $this->Tags->get($id); + $this->set(compact('tag')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + if (!$this->logged_user->hasCapability(['configuration.tags.add'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tag = $this->Tags->newEmptyEntity(); + if ($this->request->is('post')) { + $tag = $this->Tags->patchEntity($tag, $this->request->getData()); + if ($this->Tags->save($tag, ['associated' => ['ControllableObjects']])) { + $this->Flash->success(__('Il nuovo tag è stato creato')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore nella creazione del nuovo tag.') . json_encode($tag->getErrors())); + } + $this->set(compact('tag')); + } + + /** + * Edit method + * + * @param string|null $id Tag id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + if (!$this->logged_user->hasCapability(['configuration.tags.edit'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tag = $this->Tags->find()->contain(['ControllableObjects'])->where(['Tags.id' => $id])->first(); + if ($this->request->is(['patch', 'post', 'put'])) { + $tag = $this->Tags->patchEntity($tag, $this->request->getData(), ['filename_as_tag' => true, 'associated' => ['ControllableObjects' => ['associated' => ['Attachments']]]]); + if ($this->Tags->save($tag)) { + $this->Flash->success(__('Il tag è stato salvato.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante il salvataggio del tag.') . json_encode($tag->getErrors())); + } + $this->set(compact('tag')); + } +} diff --git a/idrocap_wa/src/Controller/TelegramChatsController.php b/idrocap_wa/src/Controller/TelegramChatsController.php new file mode 100644 index 0000000..01ac143 --- /dev/null +++ b/idrocap_wa/src/Controller/TelegramChatsController.php @@ -0,0 +1,76 @@ +TelegramChats->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'telegram_chat')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $telegram_chat = $this->TelegramChats->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 5, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $telegram_chat = $this->TelegramChats->patchEntity($telegram_chat, $this->request->getData()); + if ($this->TelegramChats->save($telegram_chat)) { + $this->Flash->success(__('La Chat Telegram è stata aggiunta con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta della Chat Telegram')); + } + $this->set(compact('actor', 'telegram_chat')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $telegram_chat = $this->TelegramChats->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->TelegramChats->Deliveries->Actors->get($telegram_chat->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'telegram_chat')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $telegram_chat = $this->TelegramChats->patchEntity($telegram_chat, $this->request->getData()); + if ($this->TelegramChats->save($telegram_chat)) { + $this->Flash->success(__('La Chat Telegram è stata modificata con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $telegram_chat->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica della Chat Telegram. Riprovare di nuovo')); + } + $this->set(compact('actor', 'telegram_chat')); + } +} diff --git a/idrocap_wa/src/Controller/UsersController.php b/idrocap_wa/src/Controller/UsersController.php new file mode 100644 index 0000000..ec1b375 --- /dev/null +++ b/idrocap_wa/src/Controller/UsersController.php @@ -0,0 +1,624 @@ +Authentication->allowUnauthenticated(['logout', 'login', 'login_oidc', 'login_oidc_authenticated', 'passwordRecovery', 'chooseNewPassword', 'oneTimePassword', 'add_citizen', 'verify_citizen']); + } + + public function viewClasses(): array + { + return [JsonView::class, CustomCsvView::class]; + } + + public function login_oidc() + { + OpenIdConnectClient::authorize( + Configure::read('App.oidc.authUrl'), + Configure::read('App.oidc.clientId'), + Configure::read('App.oidc.scopes'), + Configure::read('App.oidc.redirectUri') + ); + } + + public function login_oidc_authenticated() + { + try { + $access_token = OpenIdConnectClient::get_access_token( + Configure::read('App.oidc.tokenUrl'), + Configure::read('App.oidc.issuer'), + Configure::read('App.oidc.clientId'), + Configure::read('App.oidc.clientSecret'), + Configure::read('App.oidc.redirectUri') + ); + $userinfo = OpenIdConnectClient::get_user_info(Configure::read('App.oidc.userinfoUrl'), Configure::read('App.oidc.userinfo_claim_key'), $access_token); + $userinfo_claim_value = $userinfo[Configure::read('App.oidc.userinfo_claim_key')]; + $user = $this->Users->find()->where(['Users.' . Configure::read('App.oidc.usermodel_matching_attribute') => $userinfo_claim_value]); + if ($user->count() > 1) throw new \Exception(__('Non è stato possibile identificare in maniera univoca l\'utente in base all\'attributo \' {0} \' ricevuto dal provider', Configure::read('App.oidc.userinfo_claim_key'))); + $user = $user->first(); + $isUserVerified = $user?->is_verified ?? false; + if ($user && $isUserVerified) { + $this->Authentication->setIdentity($user); + } else { + if (!$user) { + $citizenRegistrationDTO = (new \App\WGS\Utils\Dto\Users\CitizenRegistrationDTO()) + ->setShowAlert(true) + // attenzione!!!!!! se $userinfo_claim_value NON COINCIDE CON IL CF, NON FUNZIONA + !!!!!!!!!!!!!!!!!!!!!!!!!! + ->setFiscalCode($userinfo[Configure::read('App.oidc.userinfo_claim_key')] ?? '') + ->setName($userinfo['given_name'] ?? '') + ->setSurname($userinfo['family_name'] ?? '') + ->setGender($userinfo['gender'] ?? '') + ->setBirthdate($userinfo['birthdate'] ?? ''); + $this->request->getSession()->write('showCitizenRegistration', $citizenRegistrationDTO); + $errorMessage = __('Errore durante l\'autenticazione mediante {0} "Utente non trovato". Riprovare di nuovo o utilizzare le credenziali di accesso', Configure::read('App.oidc.idp_name', 'OpenID Connect')); + } else if ($user && !$isUserVerified) { + $errorMessage = __('Utente non verificato. Controlla la tua email per completare la verifica.'); + } + $this->Flash->error($errorMessage); + } + return $this->redirect('/'); + } catch (\Exception $e) { + $this->Flash->error(__('Errore durante l\'autenticazione mediante {0} "{1}". Riprovare di nuovo o utilizzare le credenziali di accesso', Configure::read('App.oidc.idp_name', 'OpenID Connect'), $e->getMessage())); + return $this->redirect('/'); + } + } + + /** + * index + * + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function index() + { + if (!$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $users = $this->Users->find() + ->contain(['Actors', 'Organisations' => ['Actors', 'OrganisationActors']]); + + if (!$this->logged_user->hasCapability('configuration.users.read')) { + $users = $users->where(['Users.organisation_id' => $this->logged_user->organisation_id]); + } + + $this->set('total_users', $users->count()); + // applichiamo gli eventuali filtri presenti: + $users = $this->applyFilters($users); + $this->set('filtered_users', $users->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $users = $users + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->id == $row->id || ($this->logged_user->organisation_id == $row->organisation_id && $this->logged_user->hasCapability('configuration.users.edit_foo')) || $this->logged_user->hasCapability('configuration.users.edit'); + $row->can_delete = $this->logged_user->id != $row->id && (($this->logged_user->organisation_id == $row->organisation_id && $this->logged_user->hasCapability('configuration.users.delete_foo')) || $this->logged_user->hasCapability('configuration.users.delete')); + return $row; + }); + }); + } + + $this->paginate = [ + 'sortableFields' => ['surname', 'name', 'username', 'OrganisationActors.description'], + ]; + + $this->set('users', $this->getRequest()->is(['json', 'xml', 'csv']) ? $users : $this->paginate($users)); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('configuration.users.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Cognome'), + __('Nome'), + __('Username'), + __('Recapiti'), + __('Profili'), + __('Organizzazione'), + ]; + $extract = [ + 'surname', + 'name', + 'username', + function (array $row) { + return $row['actor']['contacts']; + }, + 'profiles', + function (array $row) { + return $row['organisation']['organisation_actor']['description']; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("users_$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'users'); + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id = null) + { + if ($this->logged_user->id != $id && !$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $user = $this->Users->get($id, contain: ['Actors', 'Languages', 'Organisations' => ['Actors']]); + + if (!$this->logged_user->hasCapability('configuration.users.read') && $this->logged_user->organisation_id != $user->organisation_id && $this->logged_user->id != $user->id) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $user->can_handle_contacts = $this->logged_user->canViewContactsForActor($this->Users->Actors->get($user->actor_id, contain: ['Users'])); + $user->can_edit = $this->logged_user->hasCapability('configuration.users.edit') || $this->logged_user->organisation_id == $user->organisation_id && $this->logged_user->hasCapability('configuration.users.edit_foo') || $this->logged_user->id == $user->id; + $user->can_delete = $this->logged_user->id != $user->id && (($this->logged_user->organisation_id == $user->organisation_id && $this->logged_user->hasCapability('configuration.users.delete_foo')) || $this->logged_user->hasCapability('configuration.users.delete')); + + $this->set(compact('user')); + $this->viewBuilder()->setOption('serialize', 'user'); + } + + /** + * add + * + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability(['configuration.users.add', 'configuration.users.add_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $can_view_profiles = $this->logged_user->hasCapability('configuration.groups.read'); + $can_handle_profiles = $can_view_profiles && ($this->logged_user->hasCapability('configuration.users.profiles') || $this->fetchTable('Users')->getAssociableUserGroups()->count() > 0); + + $user = $this->Users->newEmptyEntity(); + + $default_profiles = $this->Users->Groups->find() + ->contain(['Actors']) + ->where(['Groups.is_default' => 1]) + ->all() + ->toArray(); + + $user['groups'] = $default_profiles; + + if ($this->request->is('post')) { + $user = $this->Users->patchEntity($user, $this->request->getData()); + + if (!$can_handle_profiles) $user['groups'] = $default_profiles; + + if ($this->Users->save($user)) { + $this->Flash->success(__('Utente creato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la creazione dell\'utente')); + } + $organisations = $this->Users->Organisations->find('list')->contain(['Actors'])->order(['Actors.description' => 'ASC']); + if (!$this->logged_user->hasCapability('configuration.users.add')) $organisations = $organisations->where(['Organisations.id' => $this->logged_user->organisation_id]); + $languages = $this->Users->Languages->find('list'); + $groups = $this->fetchTable('Users')->getAssociableUserGroups(as_list: true)->order(['Groups.description' => 'ASC']); + $this->set('today', DateTime::now()); + $this->set(compact('user', 'organisations', 'languages', 'groups', 'can_view_profiles', 'can_handle_profiles')); + } + + /** + * edit + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + if ($this->logged_user->id != $id && !$this->logged_user->hasCapability(['configuration.users.edit', 'configuration.users.edit_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $can_view_profiles = $this->logged_user->hasCapability('configuration.groups.read'); + $can_handle_profiles = $can_view_profiles && ($this->logged_user->hasCapability('configuration.users.profiles') || $this->fetchTable('Users')->getAssociableUserGroups()->count() > 0); + + $user = $this->Users->get($id, contain: ['Actors', 'Groups', 'Languages', 'Organisations' => ['Actors']]); + if ($this->request->is(['patch', 'post', 'put'])) { + $user->setAccess('groups', $can_handle_profiles); + $user = $this->Users->patchEntity($user, $this->request->getData()); + + if ($this->Users->save($user)) { + $this->Flash->success(__('Utente "{0}" modificato con successo.', $user->actor->description)); + + return $this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo']) ? $this->redirect(['action' => 'index']) : $this->redirect('/'); + } + $this->Flash->error(__('Errore durante la modifica dell\'utente "{0}". Riprovare di nuovo.', $user->actor->description)); + } + $organisations = $this->Users->Organisations->find('list')->contain(['Actors'])->order(['Actors.description' => 'ASC']); + if (!$this->logged_user->hasCapability('configuration.users.edit')) $organisations = $organisations->where(['Organisations.id' => $this->logged_user->organisation_id]); + $languages = $this->Users->Languages->find('list'); + $groups = $this->fetchTable('Users')->getAssociableUserGroups(as_list: true)->order(['Groups.description' => 'ASC']); + $this->set('today', DateTime::now()); + $this->set(compact('user', 'organisations', 'languages', 'groups', 'can_view_profiles', 'can_handle_profiles')); + } + + /** + * delete + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + if (!$this->logged_user->hasCapability(['configuration.users.delete', 'configuration.users.delete_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $user = $this->Users->get($id, contain: ['Actors']); + + if ($this->logged_user->id == $user->id || ($this->logged_user->organisation_id != $user->organisation_id && !$this->logged_user->hasCapability('configuration.users.delete'))) throw new ForbiddenException(__('Non hai i permessi necessari')); + + if ($this->Users->Actors->delete($user->actor)) { + $this->Flash->success(__('L\'utente "{0}" è stato cancellato con successo', $user->actor->description)); + } else { + $this->Flash->error(__('Errore durante la cancellazione dell\'utente "{0}". Riprovare di nuovo.', $user->actor->description)); + } + + return $this->redirect(['action' => 'index']); + } + + /** + * login + * + * @return \Cake\Http\Response + */ + public function login() + { + $result = $this->Authentication->getResult(); + // If the user is logged in send them away. + if ($result->isValid()) { + $user = $this->Authentication->getIdentity(); + $user->timezone = $this->request->getData('user_timezone', Configure::read('App.defaultUserTimezone')); + // se per qualche motivo il form restituisce "" stringa vuota per il timezone, impostiamo invece il default! + if (empty($user->timezone)) $user->timezone = Configure::read('App.defaultUserTimezone'); + $this->fetchTable('Users')->save($user); + $target = $this->Authentication->getLoginRedirect() ?? '/'; + $this->request->getSession()->write("oidc", null); + return $this->redirect($target); + } + + if ($this->request->is('post')) { + $authError = $this->request->getSession()->read('AuthError'); + if ($authError) { + $this->Flash->error($authError); + $this->request->getSession()->delete('AuthError'); + } else { + $this->Flash->error('username e/o password errati'); + } + } + $login_citizen_registration = $this->request->getSession()->read('showCitizenRegistration'); + $this->set(compact('login_citizen_registration')); + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ho dimenticato la mia password')); + $this->set('login_layout_link_action', 'passwordRecovery'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + if (isset($login_citizen_registration) && $login_citizen_registration->isShowAlert()) { + $login_citizen_registration_copy = clone $login_citizen_registration; + $login_citizen_registration_copy->setShowAlert(false); + $this->request->getSession()->write('showCitizenRegistration', $login_citizen_registration_copy); + } + } + + /** + * logout + * + * @return \Cake\Http\Response + */ + public function logout() + { + $this->Authentication->logout(); + + if ($this->request->getSession()->read('oidc')) { + OpenIdConnectClient::logout( + Configure::read('App.oidc.logoutUrl'), + Configure::read('App.oidc.clientId'), + Configure::read('App.oidc.postLogoutRedirectUri') + ); + } + + $this->Flash->success(__('Logout eseguito con successo.')); + return $this->redirect(['controller' => 'Users', 'action' => 'login']); + } + + /** + * executePasswordRecovery + * + * @param \App\Model\Entity\User $user + * @param String $email + * @param String|Null $password_recovery_token + * @return String|Null + */ + private function executePasswordRecovery(\App\Model\Entity\User $user, String $email, String|Null $password_recovery_token = null): String|Null + { + $user->password_recovery_token = $password_recovery_token ?? sha1($this->gen_random_code(40)); + + if (!$this->Users->save($user)) return null; + + $options = []; + $options['user_id'] = $user->id; + $options['username'] = $user->username; + $options['email'] = $email; + $options['type'] = 'users'; + $options['password_recovery_token'] = $user->password_recovery_token; + $this->sendNotifications(null, 'password_recovery', $options); + return $user->password_recovery_token; + } + + /** + * passwordRecovery + * + * @return \Cake\Http\Response + */ + public function passwordRecovery() + { + if ($this->request->is('post')) + { + if (empty($this->request->getData('email'))) { + $this->Flash->error(__('Inserire un indirizzo email valido!')); + return $this->redirect(['action' => 'passwordRecovery']); + } + + $email = $this->Users->Actors->Deliveries->Emails->find() + ->contain(['Deliveries' => ['Actors' => ['Users']]]) + ->where(['Emails.value' => $this->request->getData('email')]) + ->first(); + + if (isset($email->delivery->actor->user)) + { + $this->executePasswordRecovery($email->delivery->actor->user, $this->request->getData('email')); + $this->Flash->success(__('A breve riceverai un\'email all\'indirizzo "{0}" con le istruzioni per eseguire il reset della password per il tuo account con username "{1}".', $this->request->getData('email'), $email->delivery->actor->user->username)); + return $this->redirect(['action' => 'login']); + } + else + { + $this->Flash->error(__('L\'indirizzo email inserito non risulta presente')); + return $this->redirect(['action' => 'passwordRecovery']); + } + } + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ritorna al login')); + $this->set('login_layout_link_action', 'login'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + } + + /** + * chooseNewPassword + * + * @param String $token + * @return \Cake\Http\Response + */ + public function chooseNewPassword($token) + { + $user = $this->Users->find()->contain(['Actors', 'Organisations'])->where(['Users.password_recovery_token' => $token])->first(); + + if(!$user) + { + $this->Flash->error(__('Impossibile completare la procedura di recupero password.')); + return $this->redirect(['action' => 'login']); + } + + if ($this->request->is('post')) + { + if (!empty($this->request->getData('new_password')) && !empty($this->request->getData('confirm_new_password')) && $this->request->getData('new_password') == $this->request->getData('confirm_new_password')) { + $user_data = $user->toArray(); + $user_data['password'] = $this->request->getData('new_password'); + $user = $this->Users->patchEntity($user, $user_data, ['validate' => false]); + if (count($user->getError('password')) > 0) { + $this->Flash->error(implode(" - ", $user->getError('password'))); + return $this->redirect(['action' => 'chooseNewPassword', $token]); + } + + $user->password_recovery_token = null; + $user->last_change_password = new \DateTime(); + $user->password_recovery_counter = $user->password_recovery_counter+1; + + if ($this->Users->save($user)) { + $this->Flash->success('Password modificata con successo'); + return $this->redirect(['action' => 'login']); + } else { + $this->Flash->error(__('Impossibile cambiare la password')); + } + + } else { + $this->Flash->error(__('La nuova password non è valida e/o le 2 password non coincidono')); + } + } + + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ritorna al login')); + $this->set('login_layout_link_action', 'login'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + } + + public function oneTimePassword(String $otp) { + $users = $this->fetchTable('Users')->find()->where(['Users.otp' => $otp]); + if ($users->count() != 1) { + $this->Flash->error(__('Codice OTP non valido o già utilizzato. Effettua il login.')); + return $this->redirect(['action' => 'login']); + } + + $user = $users->first(); + + // controllo che otp_expires sia un datetime valido e non scaduto: + if ($user->otp_expires === null || !is_object($user->otp_expires) || get_class($user->otp_expires) != "Cake\I18n\DateTime" || !$user->otp_expires->isWithinNext(Configure::read('App.oneTimePasswordExpirationHours', 1) . ' hours')) { + $user->otp = null; + $user->otp_redirect_url = null; + $user->otp_expires = null; + $this->fetchTable('Users')->save($user); + $this->Flash->error(__('Codice OTP scaduto. Effettua il login.')); + return $this->redirect(['action' => 'login']); + } + + if ($this->request->is('post')) + { + $redirect_url = $user->otp_redirect_url ?? '/'; + $user->sys_admin = false; + $user->passepartout = false; + $user->otp = null; + $user->otp_redirect_url = null; + $user->otp_expires = null; + $this->fetchTable('Users')->save($user); + $this->getRequest()->getSession()->write('Auth', $user); + return $this->redirect($redirect_url); + } + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ritorna al login')); + $this->set('login_layout_link_action', 'login'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + } + + /** + * getPhoto + * + * @param String $file_name + * @return \Cake\Http\Response + */ + public function getPhoto($file_name) + { + $photo_owner = $this->fetchTable('Users')->find()->where(['Users.photo' => $file_name])->first(); + + if (!$photo_owner) throw new NotFoundException(__('Foto utente non trovata!')); + + if ($this->logged_user->id != $photo_owner->id) { + if (!$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability(['configuration.users.read']) && $this->logged_user->organisation_id != $photo_owner->organisation_id) throw new ForbiddenException(__('Non hai i permessi necessari')); + } + + $mimetype = "image/jpeg"; + $path = Configure::read('App.userPhotoPath') . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } + + /** + * deleteUserPhoto + * + * @param Int $user_id + * @return \Cake\Http\Response + */ + public function deleteUserPhoto($user_id) + { + $user = $this->Users->get($user_id); + $user->photo = null; + if (!$this->Users->save($user)) { + $this->Flash->error(__('Errore durante l\'eliminazione della foto utente!')); + } else { + $this->Flash->success(__('Foto utente eliminata con successo')); + } + return $this->redirect(['action' => 'view', $user_id]); + } + + /** + * add_citizen + * @return \Cake\Http\Response + */ + public function add_citizen() + { + $user = $this->Users->newEmptyEntity(); + $citizenRegistrationData = $this->request->getSession()->read('showCitizenRegistration'); + if ($this->request->is('post') || $this->request->is('put')) { + $data = $this->request->getData(); + $taxCode = $data['tax_code'] ?? null; + $name = $data['name'] ?? null; + $surname = $data['surname'] ?? null; + $birthday = $data['birthday'] ?? null; + $gender = $data['gender'] ?? null; + if ($taxCode && $citizenRegistrationData && $citizenRegistrationData?->getFiscalCode() !== '' && $citizenRegistrationData->getFiscalCode() != $taxCode) { + $this->Flash->error(__('Il codice fiscale inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + elseif ($name && $citizenRegistrationData && $citizenRegistrationData?->getName() !== '' && $citizenRegistrationData->getName() != $name) { + $this->Flash->error(__('Il nome inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + elseif ($surname && $citizenRegistrationData && $citizenRegistrationData?->getSurname() !== '' && $citizenRegistrationData->getSurname() != $surname) { + $this->Flash->error(__('Il cognome inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + elseif ($birthday && $citizenRegistrationData && $citizenRegistrationData?->getBirthdate() !== '' && $citizenRegistrationData->getBirthdate() != $birthday) { + $this->Flash->error(__('La data di nascita inserita non corrisponde a quella fornita in fase di autenticazione. Riprovare.')); + } + elseif ($gender && $citizenRegistrationData && $citizenRegistrationData?->getGender() !== '' && $citizenRegistrationData->getGender() != $gender) { + $this->Flash->error(__('Il sesso inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + else { + $newCitizen = $this->Users->createCitizen($user, $data); + if ($newCitizen) { + $emails = $newCitizen?->getEmailsWithNotifications() ?? []; + $notificationEmail = $emails[0] ?? null; + $successMessage = 'Utente creato con successo.'; + if ($notificationEmail) { + $options = [ + 'user_id' => $newCitizen->id, + 'username' => $newCitizen->username, + 'email' => $notificationEmail->value, + 'type' => 'users', + 'verification_token' => $newCitizen->email_verification_code, + ]; + $this->sendNotifications(null, 'verify-citizen-registration', $options); + $successMessage = 'Utente creato con successo. Riceverai un\'email per confermare la registrazione.'; + } + $this->request->getSession()->delete('showCitizenRegistration'); + $this->Flash->success(__($successMessage)); + return $this->redirect(['action' => 'login']); + } else { + $this->Flash->error(__('Errore durante la creazione dell\'utente')); + } + } + } + + $languages = $this->Users->Languages->find('list'); + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set([ + 'today' => DateTime::now(), + 'hideLogin' => true, + 'user' => $user, + 'languages' => $languages, + 'citizenRegistrationData' => $citizenRegistrationData, + ]); + } + + + /** + * verify citizen + * @param string|null $token + * @return \Cake\Http\Response + */ + public function verify_citizen(string|null $token) + { + $token = $token ?? ''; + if ($this->Users->verifyCitizen($token)) { + $this->Flash->success(__('Utente verificato con successo.')); + return $this->redirect(['action' => 'login']); + } + + $this->Flash->error(__('Errore durante la verifica, si prega di riprovare.')); + return $this->redirect(['action' => 'login']); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingArticlesController.php b/idrocap_wa/src/Controller/WaterDrawingArticlesController.php new file mode 100644 index 0000000..0f51528 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingArticlesController.php @@ -0,0 +1,124 @@ +WaterDrawingArticles->find()->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('configuration.water_drawing_articles.edit'); + $row->can_delete = $this->logged_user->hasCapability('configuration.water_drawing_articles.delete'); + $row->can_disable = $this->logged_user->hasCapability('configuration.water_drawing_articles.disable'); + return $row; + }); + }); + $waterDrawingArticles = $this->paginate($waterDrawingArticles); + + $this->set(compact('waterDrawingArticles')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Article id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingArticle = $this->WaterDrawingArticles->get($id, contain: []); + $waterDrawingArticle->can_edit = $this->logged_user->hasCapability('configuration.water_drawing_articles.edit'); + $waterDrawingArticle->can_delete = $this->logged_user->hasCapability('configuration.water_drawing_articles.delete'); + $waterDrawingArticle->can_disable = $this->logged_user->hasCapability('configuration.water_drawing_articles.disable'); + $this->set(compact('waterDrawingArticle')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + $waterDrawingArticle = $this->WaterDrawingArticles->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, $this->request->getData()); + if ($this->WaterDrawingArticles->save($waterDrawingArticle)) { + $this->Flash->success(__('Articolo di legge salvato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante il salvataggio dell\'articolo di legge. Riprovare di nuovo.')); + } + $this->set(compact('waterDrawingArticle')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Article id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingArticle = $this->WaterDrawingArticles->get($id, contain: []); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, $this->request->getData()); + if ($this->WaterDrawingArticles->save($waterDrawingArticle)) { + $this->Flash->success(__('Articolo di legge modificato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la modifica dell\'articolo di legge. Riprovare di nuovo.')); + } + $this->set(compact('waterDrawingArticle')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Article id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingArticle = $this->WaterDrawingArticles->get($id); + if ($this->WaterDrawingArticles->delete($waterDrawingArticle)) { + $this->Flash->success(__('L\'articolo di legge è stato cancellato con successo.')); + } else { + $this->Flash->error(__('Errore durante la cancellazione dell\'articolo di legge. Riprovare di nuovo.')); + } + + return $this->redirect(['action' => 'index']); + } + + public function change_status($id){ + $waterDrawingArticle = $this->WaterDrawingArticles->get($id); + $waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, [ + 'disable' => $waterDrawingArticle->disable ? false : true + ]); + if($this->WaterDrawingArticles->save($waterDrawingArticle)){ + $this->Flash->success( $waterDrawingArticle->disable ? __('Articolo disabilitato con successo.') : __('Articolo abilitato con successo.')); + }else{ + $this->Flash->error( $waterDrawingArticle->disable ? __('Errore durante l\'abilitazione dell\'articolo.') : __('Errore durante la disabilitazione dell\'articolo.')); + } + return $this->redirect(['action' => 'index']); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingDerivationsController.php b/idrocap_wa/src/Controller/WaterDrawingDerivationsController.php new file mode 100644 index 0000000..fb7974a --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingDerivationsController.php @@ -0,0 +1,123 @@ +paginate = [ + 'contain' => ['WaterDrawingDerivationTypes', 'WaterDrawingPaperworks'], + ]; + $waterDrawingDerivations = $this->paginate($this->WaterDrawingDerivations); + + $this->set(compact('waterDrawingDerivations')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Derivation id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingDerivation = $this->WaterDrawingDerivations->find() + ->contain(['WaterDrawingDerivationTypes', 'WaterDrawingPaperworks']) + ->where(['WaterDrawingDerivations.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results){ + return $results->map(function ($row){ + $row->can_edit = true; + $row->can_delete = true; + return $row; + }); + })->first(); + + $this->set(compact('waterDrawingDerivation')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingDerivation = $this->WaterDrawingDerivations->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingDerivation = $this->WaterDrawingDerivations->patchEntity($waterDrawingDerivation, $this->request->getData()); + if ($this->WaterDrawingDerivations->save($waterDrawingDerivation)) { + $waterDrawingPaperworks = $this->WaterDrawingDerivations->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Il punto di prelievo è stato salvato con successo')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio del punto di prelievo.')); + } + $waterDrawingDerivationTypes = $this->WaterDrawingDerivations->WaterDrawingDerivationTypes->find()->all()->combine('id','description')->toArray(); + $this->set(compact('waterDrawingDerivation', 'waterDrawingDerivationTypes', 'water_drawing_paperwork_id')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Derivation id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingDerivation = $this->WaterDrawingDerivations->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingDerivation = $this->WaterDrawingDerivations->patchEntity($waterDrawingDerivation, $this->request->getData()); + + if ($this->WaterDrawingDerivations->save($waterDrawingDerivation)) { + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di prelievo è stato salvato con successo')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio del punto di prelievo.')); + } + $waterDrawingDerivationTypes = $this->WaterDrawingDerivations->WaterDrawingDerivationTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingDerivation', 'waterDrawingDerivationTypes')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Derivation id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingDerivation = $this->WaterDrawingDerivations->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->WaterDrawingDerivations->delete($waterDrawingDerivation)) { + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di prelievo è stato cancellato')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); + } else { + $this->Flash->error(__('Errore durante la cancellazione del punto di prelievo.')); + } + + return $this->redirect(['action' => 'view', $waterDrawingDerivation->id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingFeesController.php b/idrocap_wa/src/Controller/WaterDrawingFeesController.php new file mode 100644 index 0000000..b1d3986 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingFeesController.php @@ -0,0 +1,174 @@ +logged_user->hasCapability(['documentation.water_drawing_fees.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingFees = $this->WaterDrawingFees->find()->contain(['WaterDrawingPayments'])->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id])->formatResults(function ($result){ + return $result->map(function ($row){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_fees.delete') && (count($row->water_drawing_payments) == 0); + return $row; + }); + }); + $this->set('total_water_drawing_fees', $waterDrawingFees->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingFees = $this->applyFilters($waterDrawingFees); + $this->set('filtered_water_drawing_fees', $waterDrawingFees->count()); + $waterDrawingFees = $this->paginate($waterDrawingFees); + + $this->set(compact('waterDrawingFees', 'water_drawing_paperwork_id')); + $this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Anno'), + __('Canone'), + __('Dovuto') + ]; + $extract = [ + 'year', + 'amount', + 'to_pay' + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_fees_$water_drawing_paperwork_id-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingFees'); + } + + /** + * View method + * + * @param string|null $id Water Drawing Fee id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_fees.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingFee = $this->WaterDrawingFees->find()->contain(['WaterDrawingPayments'])->where(['WaterDrawingFees.id' => $id])->formatResults(function ($result){ + return $result->map(function ($row){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_fees.delete') && (count($row->water_drawing_payments) == 0); + return $row; + }); + })->first(); + + $waterDrawingPayments = $this->WaterDrawingFees->WaterDrawingPayments->find()->contain(['WaterDrawingFees', 'WaterDrawingPaymentTypes', 'Users'])->where(['WaterDrawingPayments.water_drawing_fee_id' => $id])->formatResults(function ($result){ + return $result->map(function ($row){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + return $row; + }); + }); + + $this->set(compact('waterDrawingFee', 'waterDrawingPayments')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingFee = $this->WaterDrawingFees->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingFee = $this->WaterDrawingFees->patchEntity($waterDrawingFee, $this->request->getData()); + if ($this->WaterDrawingFees->save($waterDrawingFee)) { + $waterDrawingPaperworks = $this->WaterDrawingFees->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Il canone annuale è stato salvato.')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il canone annuale non è stato salvato.')); + } + $this->set(compact('waterDrawingFee', 'water_drawing_paperwork_id')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Fee id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingFee = $this->WaterDrawingFees->get($id); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingFee = $this->WaterDrawingFees->patchEntity($waterDrawingFee, $this->request->getData()); + if ($this->WaterDrawingFees->save($waterDrawingFee)) { + $this->Flash->success(__('Il canone annuale è stato salvato.')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il canone annuale non è stato salvato.')); + } + $this->set(compact('waterDrawingFee')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Fee id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingFee = $this->WaterDrawingFees->get($id, contain: ['WaterDrawingPayments']); + if(count($waterDrawingFee->water_drawing_payments) > 0){ + $this->Flash->error(__('Errore. Per poter eliminare il canone bisogna eliminare i pagamenti ad esso associati.')); + return $this->redirect(['action' => 'view', $id]); + } + if ($this->WaterDrawingFees->delete($waterDrawingFee)) { + $this->Flash->success(__('Il canone annuale è stato cancellato.')); + } else { + $this->Flash->error(__('Errore. Il canone annuale non è stato cancellato.')); + } + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php b/idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php new file mode 100644 index 0000000..9859ceb --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php @@ -0,0 +1,108 @@ +paginate = [ + 'contain' => ['WaterDrawingPaperworks', 'WaterDrawingIntendedUseTypes'], + ]; + $waterDrawingIntendedUses = $this->paginate($this->WaterDrawingIntendedUses); + + $this->set(compact('waterDrawingIntendedUses')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Intended Use id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id, contain: ['WaterDrawingPaperworks', 'WaterDrawingIntendedUseTypes']); + + $this->set(compact('waterDrawingIntendedUse')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->patchEntity($waterDrawingIntendedUse, $this->request->getData()); + if ($this->WaterDrawingIntendedUses->save($waterDrawingIntendedUse)) { + $this->Flash->success(__('The water drawing intended use has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The water drawing intended use could not be saved. Please, try again.')); + } + $waterDrawingPaperworks = $this->WaterDrawingIntendedUses->WaterDrawingPaperworks->find('list')->all(); + $waterDrawingIntendedUseTypes = $this->WaterDrawingIntendedUses->WaterDrawingIntendedUseTypes->find('list')->all(); + $this->set(compact('waterDrawingIntendedUse', 'waterDrawingPaperworks', 'waterDrawingIntendedUseTypes')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Intended Use id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id, contain: []); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->patchEntity($waterDrawingIntendedUse, $this->request->getData()); + if ($this->WaterDrawingIntendedUses->save($waterDrawingIntendedUse)) { + $this->Flash->success(__('The water drawing intended use has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The water drawing intended use could not be saved. Please, try again.')); + } + $waterDrawingPaperworks = $this->WaterDrawingIntendedUses->WaterDrawingPaperworks->find('list')->all(); + $waterDrawingIntendedUseTypes = $this->WaterDrawingIntendedUses->WaterDrawingIntendedUseTypes->find('list')->all(); + $this->set(compact('waterDrawingIntendedUse', 'waterDrawingPaperworks', 'waterDrawingIntendedUseTypes')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Intended Use id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id); + if ($this->WaterDrawingIntendedUses->delete($waterDrawingIntendedUse)) { + $this->Flash->success(__('The water drawing intended use has been deleted.')); + } else { + $this->Flash->error(__('The water drawing intended use could not be deleted. Please, try again.')); + } + + return $this->redirect(['action' => 'index']); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php b/idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php new file mode 100644 index 0000000..75779cf --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php @@ -0,0 +1,124 @@ +logged_user->hasCapability('documentation.water_drawing_measurements.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeasurement = $this->WaterDrawingMeasurements->newEmptyEntity(); + $waterDrawingMeter = $this->WaterDrawingMeasurements->WaterDrawingMeters->find()->contain(['WaterDrawingIntendedUses' => ['WaterDrawingPaperworks']])->where(['WaterDrawingMeters.id' => $water_drawing_meter_id])->first(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['user_id'] = $this->logged_user->id; + $data['water_drawing_meter_id'] = $water_drawing_meter_id; + $waterDrawingMeasurement = $this->WaterDrawingMeasurements->patchEntity($waterDrawingMeasurement, $data); + if ($this->WaterDrawingMeasurements->save($waterDrawingMeasurement)) { + SnapshotsHandler::createSnapshot($waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Misurazione salvata con successo.')); + return $this->redirect(['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingMeter->id]); + } + $this->Flash->error(__('Errore durante il salvataggio della misurazione.')); + } + $this->set('today', DateTime::now()); + $this->set('water_drawing_paperwork_id', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id); + $this->set(compact('waterDrawingMeasurement', 'water_drawing_meter_id')); + } + + /** + * index + * + * @param mixed $water_drawing_paperwork_id + * @return void + */ + public function index($water_drawing_paperwork_id){ + $waterDrawingMeasurements = $this->WaterDrawingMeasurements->find()->contain(['WaterDrawingMeters' => ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses'], 'Users'])->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $water_drawing_paperwork_id]); + $this->set('total_water_drawing_measurements', $waterDrawingMeasurements->count()); + + // applichiamo gli eventuali filtri presenti: + $waterDrawingMeasurements = $this->applyFilters($waterDrawingMeasurements); + $this->set('filtered_water_drawing_measurements', $waterDrawingMeasurements->count()); + + if(!$this->getRequest()->is(['json', 'xml', 'csv'])){ + $waterDrawingMeasurements = $waterDrawingMeasurements + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->date = $row->date?->format('d/m/Y'); + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'order' => [ + 'WaterDrawingMeasurements.date' => 'DESC' + ], + ]; + + $this->set(compact('water_drawing_paperwork_id')); + $this->set('waterDrawingMeasurements', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingMeasurements : $this->paginate($waterDrawingMeasurements)); + $this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_measurements.export_csv_measurement')); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_measurements.export_csv_measurement')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $header = [ + __('N° matricola strumento di misura'), + __('Lettura Volume (m^3)'), + __('Data lettura'), + __('Utente'), + ]; + $extract = [ + function (array $row) { + return $row['water_drawing_meter']['part_number']; + }, + 'volume', + 'date', + function (array $row) { + $user = $this->fetchTable('Users')->get($row['user']['id']); + return $user; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_measurements_$water_drawing_paperwork_id-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingMeasurements'); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingMetersController.php b/idrocap_wa/src/Controller/WaterDrawingMetersController.php new file mode 100644 index 0000000..d80427e --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingMetersController.php @@ -0,0 +1,97 @@ +logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->newEmptyEntity(); + $waterDrawingIntendedUse = $this->WaterDrawingMeters->WaterDrawingIntendedUses->get($water_drawing_intended_use_id); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['water_drawing_intended_use_id'] = $water_drawing_intended_use_id; + $waterDrawingMeter = $this->WaterDrawingMeters->patchEntity($waterDrawingMeter, $data); + if ($this->WaterDrawingMeters->save($waterDrawingMeter)) { + $waterDrawingPaperworks = $this->WaterDrawingMeters->WaterDrawingIntendedUses->WaterDrawingPaperworks->get($waterDrawingIntendedUse->water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Strumento di misura salvato con successo.')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio dello strumento di misura.')); + } + $waterDrawingToolTypes = $this->WaterDrawingMeters->WaterDrawingToolTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingMeter', 'waterDrawingToolTypes', 'water_drawing_intended_use_id')); + $this->set('water_drawing_paperwork_id', $waterDrawingIntendedUse->water_drawing_paperwork_id); + } + + /** + * dismiss + * + * @param mixed $water_drawing_meter_id + * @return void + */ + public function dismiss($water_drawing_meter_id) + { + if (!$this->logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->get($water_drawing_meter_id, contain: ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingMeter = $this->WaterDrawingMeters->patchEntity($waterDrawingMeter, $this->request->getData()); + if ($this->WaterDrawingMeters->save($waterDrawingMeter)) { + $this->Flash->success(__('Strumento di misura dismesso con successo.')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante la dismissione dello strumento di misura.')); + } + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingMeter')); + } + + public function edit($water_drawing_meter_id) + { + if (!$this->logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->get($water_drawing_meter_id, contain: ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingMeter = $this->WaterDrawingMeters->patchEntity($waterDrawingMeter, $this->request->getData()); + if ($this->WaterDrawingMeters->save($waterDrawingMeter)) { + $this->Flash->success(__('Strumento di misura salvato con successo.')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio dello strumento di misura.')); + } + $waterDrawingToolTypes = $this->WaterDrawingMeters->WaterDrawingToolTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingMeter', 'waterDrawingToolTypes')); + } + + public function view($water_drawing_meter_id) + { + if (!$this->logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->get($water_drawing_meter_id, contain: ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses', 'WaterDrawingMeasurements' => function ($q){ + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }] + ); + $waterDrawingToolTypes = $this->WaterDrawingMeters->WaterDrawingToolTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingMeter', 'waterDrawingToolTypes')); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php b/idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php new file mode 100644 index 0000000..0a71852 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php @@ -0,0 +1,148 @@ +WaterDrawingPaperworkPecs->find()->contain(['Users'])->where(['WaterDrawingPaperworkPecs.water_drawing_paperwork_id' => $water_drawing_paperwork_id]); + $this->set('total_water_drawing_papwork_pecs', $waterDrawingPaperworkPecs->count()); + + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworkPecs = $this->applyFilters($waterDrawingPaperworkPecs); + $this->set('filtered_water_drawing_papwork_pecs', $waterDrawingPaperworkPecs->count()); + + $this->paginate = [ + 'order' => [ + 'WaterDrawingPaperworkPec.date' => 'DESC' + ], + ]; + $waterDrawingPaperworkPecs = $waterDrawingPaperworkPecs->formatResults(function ($results){ + return $results->map( function ($row){ + $row->can_edit_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.edit'); + $row->can_delete_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.delete'); + return $row; + }); + }); + $this->set(compact('water_drawing_paperwork_id')); + $this->set('waterDrawingPaperworkPecs', $this->paginate($waterDrawingPaperworkPecs)); + $this->set('add_documentation', $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.add')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Paperwork Pec id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->find()->contain(['WaterDrawingPaperworks', 'Users', 'ControllableObjects' => ['Attachments']])->where(['WaterDrawingPaperworkPecs.id' => $id])->formatResults(function ($results) { + return $results->map(function ($row) { + $row->can_edit_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.edit'); + $row->can_delete_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.delete'); + return $row; + }); + })->first(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkPecs'])->all()->combine('code', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperworkPec', 'tags')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->patchEntity($waterDrawingPaperworkPec, $this->request->getData()); + $waterDrawingPaperworkPec->user_id = $this->logged_user->id; + if ($this->WaterDrawingPaperworkPecs->save($waterDrawingPaperworkPec)) { + $waterDrawingPaperworks = $this->WaterDrawingPaperworkPecs->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Il documento PEC è stato salvato.')); + + return $this->redirect(['action' => 'index', $water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore.Non è stato salvato il documento PEC. ') . $waterDrawingPaperworkPec->getError('attachment')[0]); + } + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkPecs'])->all()->combine('code', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperworkPec', 'water_drawing_paperwork_id', 'tags')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Paperwork Pec id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->get($id, contain: ['ControllableObjects' => ['Attachments'], 'WaterDrawingPaperworks']); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkPecs'])->all()->combine('code', 'description')->toArray(); + if ($this->request->is(['patch', 'post', 'put'])) { + $this->log(json_encode($this->request->getData(), JSON_PRETTY_PRINT), 'debug'); + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->patchEntity($waterDrawingPaperworkPec, $this->request->getData(), ['associated' => ['ControllableObjects']]); + $this->log(json_encode($waterDrawingPaperworkPec, JSON_PRETTY_PRINT), 'debug'); + if ($this->WaterDrawingPaperworkPecs->save($waterDrawingPaperworkPec)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperworkPec->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il documento PEC è stato salvato.')); + + return $this->redirect(['action' => 'index', $waterDrawingPaperworkPec->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore.Non è stato salvato il documento PEC. ') . $waterDrawingPaperworkPec->getError('attachment')[0]); + } + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperworkPec', 'tags')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Paperwork Pec id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->get($id); + if ($this->WaterDrawingPaperworkPecs->delete($waterDrawingPaperworkPec)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperworkPec->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il documento PEC è stato cancellato.')); + } else { + $this->Flash->error(__('Errore.Non è stato cancellato il documento PEC.')); + } + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPaperworkPec->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingPaperworksController.php b/idrocap_wa/src/Controller/WaterDrawingPaperworksController.php new file mode 100644 index 0000000..20a9da4 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingPaperworksController.php @@ -0,0 +1,1775 @@ +logged_user->hasCapability(['documentation.water_drawing_snapshots.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->set('water_drawing_paperwork_id', $water_drawing_paperwork_id); + $this->set('can_export_snapshots', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots.export_csv'])); + + $water_drawing_paperwork = $this->fetchTable('WaterDrawingPaperworks')->get($water_drawing_paperwork_id); + $this->set('waterDrawingPaperwork', $water_drawing_paperwork); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.water_drawing_paperwork_id' => $water_drawing_paperwork_id, 'UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $this->paginate = [ + 'limit' => 25, + 'order' => [ + 'when' => 'DESC' + ], + ]; + + $this->set('unpackedWaterDrawingPaperworkSnapshots', $this->getRequest()->is(['json', 'xml', 'csv']) ? $unpackedWaterDrawingPaperworkSnapshots : $this->paginate($unpackedWaterDrawingPaperworkSnapshots)); + + $this->viewBuilder()->setOption('serialize', 'unpackedWaterDrawingPaperworkSnapshots'); + } + + /** + * index_snapshots_csv + * + * @param mixed $water_drawing_paperwork_id + * @return void + */ + public function index_snapshots_csv($water_drawing_paperwork_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability('documentation.water_drawing_snapshots.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.water_drawing_paperwork_id' => $water_drawing_paperwork_id, 'UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $headers = [ + __('Data'), + __('Da (operatore)'), + __('Azione'), + __('Stato pratica'), + __('Assegnatario Genio Civile'), + __('Assegnatario DRAR'), + ]; + $extract = [ + function (array $row) { + return isset($row['when']) ? (new DateTime($row['when']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + 'who', + 'what', + 'water_drawing_paperwork_status', + 'gc_user', + 'drar_user', + ]; + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + + return $this->streamCsvResponse( + $unpackedWaterDrawingPaperworkSnapshots, + "water_drawing_paperwork-$water_drawing_paperwork_id-snapshots_$timestamp.csv", + $extract, + $headers + ); + } + + public function view_snapshot($snapshot_id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $snapshot = $this->fetchTable('Snapshots')->get($snapshot_id); + + $co = SnapshotsHandler::getControllableObjectFromSnapshotWithId((int)$snapshot_id); + + $this->set('back_to_logs', !empty($this->request->getQuery('origin')) && $this->request->getQuery('origin') == 'logs'); + $this->set('date', $snapshot->date); + $this->set('previous_snapshot_id', $this->fetchTable('Snapshots')->find()->where(['Snapshots.id <' => $snapshot_id, 'Snapshots.controllable_object_id' => $co->id, 'Snapshots.unpacked_with_version' => SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion()])->order(['Snapshots.id' => 'DESC'])->first()?->id); + $this->set('next_snapshot_id', $this->fetchTable('Snapshots')->find()->where(['Snapshots.id >' => $snapshot_id, 'Snapshots.controllable_object_id' => $co->id, 'Snapshots.unpacked_with_version' => SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion()])->order(['Snapshots.id' => 'ASC'])->first()?->id); + + $co->water_drawing_paperwork->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $co->water_drawing_paperwork->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + + $this->set('waterDrawingPaperwork', $co->water_drawing_paperwork); + $this->set('waterDrawingPaperworkHistories', $co->water_drawing_paperwork->water_drawing_paperwork_histories); + + $waterDrawingPayments = collection($co->water_drawing_paperwork->water_drawing_fees) + ->reduce(function ($acc, $water_drawing_fee) { + $water_drawing_fee_year = $water_drawing_fee->year; + $water_drawing_fee->water_drawing_payments = collection($water_drawing_fee->water_drawing_payments)->map(function ($water_drawing_payment, $key) use ($water_drawing_fee_year) { + $water_drawing_payment->amount = !empty($water_drawing_payment->amount) ? $water_drawing_payment->amount . ' €' : null; + $water_drawing_payment->payment_date = $water_drawing_payment->payment_date?->format('Y/m/d'); + $water_drawing_payment->created = isset($water_drawing_payment->created) ? (new DateTime($water_drawing_payment->created))->i18nFormat('Y/MM/dd HH:mm:ss', $this->logged_user->timezone) : null; + $water_drawing_payment->water_drawing_fee_year = $water_drawing_fee_year; + return $water_drawing_payment; + })->toArray(); + return array_merge($acc, $water_drawing_fee->water_drawing_payments); + }, []); + + $this->set('waterDrawingPayments', $waterDrawingPayments); + + $this->set('numberOfAttachments', count($co->child_attachments)); + $this->set('attachments', $co->child_attachments); + + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('WaterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('logged_user_id', $this->logged_user->id); + } + + public function index_snapshots_all() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->set('can_export_snapshots_all', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots.export_all_csv'])); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $this->paginate = [ + 'limit' => 25, + 'order' => [ + 'when' => 'DESC' + ], + ]; + + $this->set('unpackedWaterDrawingPaperworkSnapshots', $this->getRequest()->is(['json', 'xml', 'csv']) ? $unpackedWaterDrawingPaperworkSnapshots : $this->paginate($unpackedWaterDrawingPaperworkSnapshots)); + + $this->viewBuilder()->setOption('serialize', 'unpackedWaterDrawingPaperworkSnapshots'); + } + + /** + * index_snapshots_all_csv + * + * @return void + */ + public function index_snapshots_all_csv() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability('documentation.water_drawing_snapshots.export_all_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $headers = [ + __('Data'), + __('Da (operatore)'), + __('Azione'), + __('ID Pratica'), + __('Stato pratica'), + __('Assegnatario Genio Civile'), + __('Assegnatario DRAR'), + ]; + $extract = [ + function (array $row) { + return isset($row['when']) ? (new DateTime($row['when']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + 'who', + 'what', + 'water_drawing_paperwork_id', + 'water_drawing_paperwork_status', + 'gc_user', + 'drar_user', + ]; + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + + return $this->streamCsvResponse( + $unpackedWaterDrawingPaperworkSnapshots, + "water_drawing_paperwork_snapshots_all_$timestamp.csv", + $extract, + $headers + ); + } + + /** + * Index method + * + * @return \Cake\Http\Response|null|void Renders view + */ + public function index() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find() + ->contain(['Applicants', 'ControllableObjects', 'WaterDrawingPaperworkStatuses']); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); + } + + $this->set('total_water_drawing_paperworks', $waterDrawingPaperworks->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworks = $this->applyFilters($waterDrawingPaperworks); + $this->set('filtered_water_drawing_paperworks', $waterDrawingPaperworks->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $waterDrawingPaperworks = $waterDrawingPaperworks + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->release_date = $row->release_date?->format('Y/m/d'); + $row->expiration_date = $row->expiration_date?->format('Y/m/d'); + $row->controllable_object->created = $row->controllable_object->created?->format('Y/m/d H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('Y/m/d H:i:s'); + $row->can_edit = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province') && $row?->authority_province === $this->logged_user?->organisation_province) && + ($this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5) || + ($this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4))) || + (($row->water_drawing_paperwork_status_id == 3 || $row->water_drawing_paperwork_status_id == 5) || + ($row->water_drawing_paperwork_status_id == 8) ? false : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_scan')) ; + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete') || $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_own_province') && $row?->authority_province === $this->logged_user?->organisation_province; + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + 'order' => [ + 'ControllableObjects.created' => 'DESC', + ], + ]; + if(!($this->getRequest()->is(['json', 'xml', 'csv']))){ + $waterDrawingPaperworks = $this->paginate($waterDrawingPaperworks); + if($waterDrawingPaperworks->currentPage() > $waterDrawingPaperworks->pageCount()){ + $queryParams = $this->getRequest()->getQueryParams(); + $queryParams['page'] = 1; + $this->setRequest($this->getRequest()->withQueryParams($queryParams)); + } + } + + $this->set('waterDrawingPaperworks', $waterDrawingPaperworks); + + $this->set('can_export_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_list.export_csv'])); + $this->set('can_export_all_payments_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_all_payments.export_csv_payment'])); + $this->set('can_view_all_snapshots', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])); + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPaperworks'); + } + + /** + * index_csv + * + * @return void + */ + public function index_csv() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks_list.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find() + ->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses']); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); + } + + $headers = [ + __('ID'), + __('Codice identificativo'), + __('Stato'), + __('Provincia'), + __('Data di rilascio'), + __('Scadenza'), + __('Creata'), + __('Modificata'), + ]; + + $extract = [ + 'id', + 'authority_identification_code_civil_engineering_office', + function (array $row) { + return $row['water_drawing_paperwork_status']['description'] ?? ''; + }, + 'authority_province', + function (array $row) { + return isset($row['release_date']) ? (new DateTime($row['release_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['expiration_date']) ? (new DateTime($row['expiration_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['created']) ? (new DateTime($row['controllable_object']['created']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['modified']) ? (new DateTime($row['controllable_object']['modified']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + ]; + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + + return $this->streamCsvResponse( + $waterDrawingPaperworks, + "water_drawing_paperworks-$timestamp.csv", + $extract, + $headers + ); + } + + /** + * view method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $organisation = $this->getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $this->logged_user->organisation_id])->first(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find() + ->contain([ + 'WaterDrawingPaperworkPecs', + 'WaterDrawingFees', + 'GcUsers' => ['Organisations'], + 'DrarUsers' => ['Organisations'], + 'WaterDrawingReturnPoints', + 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], + 'WaterDrawingPaperworkStatuses', + 'ControllableObjects' => ['Attachments' => ['Tags']], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q) { + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ]) + ->where(['WaterDrawingPaperworks.id' => $id]); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); + } + + $waterDrawingPaperwork = $waterDrawingPaperwork->formatResults(function (\Cake\Collection\CollectionInterface $results) use ($organisation) { + return $results->map(function ($row) use ($organisation) { + if (!$organisation && !empty($row['gc_user'])) { + return $row; + } + $row->can_view_snapshots = $this->logged_user->hasCapability('documentation.water_drawing_snapshots.view'); + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province') && $row?->authority_province === $this->logged_user?->organisation_province) && (isset($row->gc_user_id) && $this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5) || ($this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4)); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_own_province') && $row?->authority_province === $this->logged_user?->organisation_province); + $row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && ((isset($row->drar_user_id) && $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -3) || (isset($row->gc_user_id) && $this->logged_user->id == $row->gc_user_id && $row->water_drawing_paperwork_status_id === 10)); + $row->can_send_to_drar = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province')) && $row?->authority_province === $this->logged_user?->organisation_province) && $row->water_drawing_paperwork_status_id === -1 && $row->check_sdd && isset($row->gc_user_id) && $row->gc_user_id == $this->logged_user->id; + $row->can_send_to_gc = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province')) && $row?->authority_province === $this->logged_user?->organisation_province) && $row->water_drawing_paperwork_status_id === -4 && $row->check_dec && isset($row->drar_user_id) && $row->drar_user_id == $this->logged_user->id; + $row->can_assign_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && $row->water_drawing_paperwork_status_id <= -2 && $organisation->organisation_type_id == 6; + $row->can_assign_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && ($row->water_drawing_paperwork_status_id === 9 || !isset($row->gc_user_id) || $organisation->organisation_type_id == $row->gc_user->organisation->organisation_type_id); + $row->can_add_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.add'); + $row->can_edit_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.edit'); + $row->can_delete_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.delete'); + if ($row->water_drawing_paperwork_status_id === -5) { + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit') || $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + $row->can_add_meter = $this->logged_user->hasCapability('documentation.water_drawing_meters.add'); + $row->can_add_measurements = $this->logged_user->hasCapability('documentation.water_drawing_measurements.add'); + $row->can_view_measurements = true; + } + if ($row->water_drawing_paperwork_status_id == -4) { + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit') || $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + $row->can_submit_antimafia_request = ($this->logged_user->id == $row->drar_user_id) && (!isset($row->water_drawing_antimafia_certification_requests[0])); + $row->can_antimafia_request_to_anac = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($row->water_drawing_antimafia_certification_requests[0]) && ($row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1)); + $row->can_request_self_certification = ($this->logged_user->id == $row->drar_user_id) && (isset($row->water_drawing_antimafia_certification_requests[0]) && (new DateTime($row->water_drawing_antimafia_certification_requests[0]->created))->diffInDays(\Cake\I18n\DateTime::now()) > 30); + $row->can_upload_antimafia_attachment = (isset($row->water_drawing_antimafia_certification_requests[0]) && ( + (($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && !($row->check_dam)) || + (($this->logged_user->id == $row->gc_user_id) && $row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) + )); + } + return $row; + }); + })->first(); + + if (!isset($waterDrawingPaperwork)) { + throw new NotFoundException(__('Pratica non trovata')); + } + + $waterDrawingPaperworkHistories = $this->fetchTable('WaterDrawingPaperworkHistories')->find()->contain(['Users' => ['Actors'], 'ControllableObjects'])->order(['WaterDrawingPaperworkHistories.created' => 'DESC'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id])->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->created = $row->created?->format('Y/m/d'); + return $row; + })->toArray(); + }); + + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $id]) + ->order(['WaterDrawingPayments.created' => 'DESC']) + ->limit(5) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('d/m/Y'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperwork', 'waterDrawingPayments', 'WaterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('waterDrawingPaperworkHistories', $this->paginate($waterDrawingPaperworkHistories)); + $this->set('logged_user_id', $this->logged_user->id); + } + + /** + * view_scan method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view_scan($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find() + ->contain([ + 'WaterDrawingPaperworkPecs', + 'WaterDrawingFees', + 'GcUsers' => ['Organisations'], + 'DrarUsers' => ['Organisations'], + 'WaterDrawingReturnPoints', + 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], + 'WaterDrawingPaperworkStatuses', + 'ControllableObjects' => ['Attachments' => ['Tags']], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q) { + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ]) + ->where(['WaterDrawingPaperworks.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + $row->can_edit = ($row->water_drawing_paperwork_status_id == 3 || $row->water_drawing_paperwork_status_id == 5) ? false : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_scan'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete'); + $row->can_validate = ($row->water_drawing_paperwork_status_id != 3 && $row->water_drawing_paperwork_status_id != 5) ? false : ($row->water_drawing_paperwork_status_id == 3 ? $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.first_level_scan') : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.second_level_scan')); + $row->can_send_to_validation = ( + (($row->water_drawing_paperwork_status_id == 1 || $row->water_drawing_paperwork_status_id == 2) && isset($row->applicants, $row->applicants[0]->tax_code, $row->authority_identification_code_civil_engineering_office)) + || $row->water_drawing_paperwork_status_id == 4); + return $row; + }); + }); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperwork = $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); + } + $waterDrawingPaperwork = $waterDrawingPaperwork->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + $waterDrawingPaperworkHistories = $this->fetchTable('WaterDrawingPaperworkHistories')->find()->contain(['Users' => ['Actors'], 'ControllableObjects'])->order(['WaterDrawingPaperworkHistories.created' => 'DESC'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id])->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->created = $row->created?->format('Y/m/d'); + return $row; + })->toArray(); + }); + + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $id]) + ->order(['WaterDrawingPayments.created' => 'DESC']) + ->limit(5) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('d/m/Y'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperwork', 'waterDrawingPayments', 'WaterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('waterDrawingPaperworkHistories', $this->paginate($waterDrawingPaperworkHistories)); + $this->set('logged_user_id', $this->logged_user->id); + } + + /** + * add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.add', 'documentation.water_drawing_paperworks.add_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->newEmptyEntity(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id NOT IN' => [-11, -14, -15], 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.add', + 'documentation.water_drawing_paperworks.add_own_province' + ])) { + $data['authority_province'] = $this->logged_user?->organisation_province; + $this->set("authority_civil_engineer_code", SicilyProvinces::getAuthorityEngineerCode($this->logged_user?->organisation_province)); + $this->set("hide_authority_province", true); + } + + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['scanned'] = 0; + $data['water_drawing_paperwork_status_id'] = -1; + $data['gc_user_id'] = $this->logged_user->id; + + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true, 'associated' => ['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['associated' => ['CadastralCropTypes']]]]); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . $waterDrawingPaperwork->getError('attachment')[0]); + } + $waterDrawingDerivationTypes = $this->getTableLocator()->get('WaterDrawingDerivationTypes')->find()->all()->combine('id', 'description')->toArray(); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->where(['WaterDrawingArticles.disable IS NOT' => 1])->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperwork', 'tags', 'waterDrawingDerivationTypes', 'WaterDrawingArticles')); + } + + /** + * add_scan method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add_scan() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.add_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->newEmptyEntity(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['scanned'] = 1; + $messages = $this->WaterDrawingPaperworks->checkAttachments($data); + if (count($messages) != 0) { + $error = ''; + foreach ($messages as $message) $error = $error . $message . " "; + $this->Flash->error(__("Errore con gli allegati. ") . $error); + } else { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'edit_scan', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . json_encode($waterDrawingPaperwork->getErrors())); + } + } + $this->set(compact('waterDrawingPaperwork', 'tags')); + } + + public function edit($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit', 'documentation.water_drawing_paperworks.edit_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->where(['WaterDrawingPaperworks.id' => $id]) + ->contain(['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['CadastralCropTypes']]); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.edit', + 'documentation.water_drawing_paperworks.edit_own_province' + ])) { + $waterDrawingPaperwork->where(['WaterDrawingPaperworks.authority_province' => $this->logged_user->organisation_province]); + $this->set("hide_authority_province", true); + $this->set("authority_civil_engineer_code", SicilyProvinces::getAuthorityEngineerCode($this->logged_user?->organisation_province)); + } + + $waterDrawingPaperwork = $waterDrawingPaperwork->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -2) { + $this->Flash->error(__('La pratica di attingimento è in stato di assegnazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -3) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if (($waterDrawingPaperwork->water_drawing_paperwork_status_id == -1 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == -5) && $waterDrawingPaperwork->gc_user_id != $this->logged_user->id) { + $this->Flash->error(__('La pratica di attingimento è in carico al Genio Civile. Non puoi modificare questa pratica.')); + return $this->redirect(['action' => 'index']); + } + if (($waterDrawingPaperwork->water_drawing_paperwork_status_id == -4) && $waterDrawingPaperwork->drar_user_id != $this->logged_user->id) { + $this->Flash->error(__('La pratica di attingimento è in carico al DRAR. Non puoi modificare questa pratica.')); + return $this->redirect(['action' => 'index']); + } + + if ($this->request->is(['patch', 'post', 'put'])) { + $requestData = $this->request->getData(); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.edit', + 'documentation.water_drawing_paperworks.edit_own_province' + ])) { + $requestData['authority_province'] = $this->logged_user->organisation_province; + } + + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $requestData, ['filename_as_tag' => true, 'associated' => ['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['associated' => ['CadastralCropTypes']]]]); + + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . (isset($waterDrawingPaperwork->getError('attachment')[0]) ? $waterDrawingPaperwork->getError('attachment')[0] : null)); + } + $tags_viewer = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->all()->combine('code', 'description')->toArray(); + $tags_picker = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id NOT IN' => [-11, -14, -15], 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + $waterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->where(['WaterDrawingArticles.disable IS NOT' => 1])->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperwork', 'tags_picker', 'tags_viewer', 'waterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('user_id', $this->logged_user->id); + } + + /** + * edit_scan method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit_scan($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['CadastralCropTypes']]); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 3 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 5) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $this->request->getData(), ['associated' => ['Applicants._joinData', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['associated' => ['CadastralCropTypes']]]]); + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + $waterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->where(['WaterDrawingArticles.disable IS NOT' => 1])->all()->combine('id', 'description')->toArray(); + $tags_viewer = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->all()->combine('code', 'description')->toArray(); + $tags_picker = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id NOT IN' => [-11, -14, -15], 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + + + /* + * IA PLUGIN + * Ordino gli allegati in base alla priorità definita. + * La priorità massima è assegnata al decreto (DEC) poiché contiene più informazioni. + * Se il decreto non è presente, la seconda priorità è il disciplinare (DSC). + * Se il disciplinare non è presente, la terza priorità è la licenza (LIC). + */ + $iaHighestPriorityAttachment = $this->fetchTable('ControllableObjects') + ->Attachments->find() + ->where(['Attachments.container_controllable_object_id' => $waterDrawingPaperwork->controllable_object_id]) + ->matching('Tags', function ($q) { + return $q->where(['Tags.code IN' => ['DEC', 'DSC', 'LIC']]); + })->orderBy( + [ + 'CASE WHEN Tags.code = "DEC" THEN 1 WHEN Tags.code = "DSC" THEN 2 WHEN Tags.code = "LIC" THEN 3 ELSE 4 END' + ] + )->first(); + + $iaPluginData = []; + if ($iaHighestPriorityAttachment) { + $iaPluginData = [ + 'documentHash' => $iaHighestPriorityAttachment->file_name, + 'type' => $iaHighestPriorityAttachment->_matchingData['Tags']->code, + ]; + } + $isAiServiceEnabled = Configure::read('App.aiServiceEnabled'); + /* IA PLUGIN END */ + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperwork', 'waterDrawingArticles', 'tags_picker', 'tags_viewer', 'iaPluginData', 'intendedUseTypes', 'cadastralCropTypes', 'isAiServiceEnabled', 'wateringSystems')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.delete', 'documentation.water_drawing_paperworks.delete_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->find()->where(['WaterDrawingPaperworks.id' => $id])->contain(['Applicants', 'ControllableObjects']); + + + if ($this->logged_user->hasOnlyLowerPriorityCapability( + [ + 'documentation.water_drawing_paperworks.delete', + 'documentation.water_drawing_paperworks.delete_own_province' + ] + )) { + $waterDrawingPaperwork->where(['WaterDrawingPaperworks.authority_province' => $this->logged_user->organisation_province]); + } + + $waterDrawingPaperwork = $waterDrawingPaperwork->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + + $connection = ConnectionManager::get('default'); + $connection->begin(); + if (SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id) && $this->fetchTable('WaterDrawingPaperworks')->ControllableObjects->delete($waterDrawingPaperwork->controllable_object)) { + $connection->commit(); + $this->Flash->success(__('La pratica di attingimento con ID:"{0}" è stato cancellato con successo', $waterDrawingPaperwork->id)); + } else { + $connection->rollback(); + $this->Flash->error(__('Errore durante la cancellazione della pratica di attingimento con ID:"{0}". Riprovare di nuovo.', $waterDrawingPaperwork->id)); + } + + return $this->redirect(['action' => 'index']); + } + + /** + * applicants_water_drawing_paperworks_item_block + * + * @param mixed $id + * @return void + */ + public function applicants_water_drawing_paperworks_item_block($id, $water_id = null) + { + if (isset($water_id)) { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($water_id); + $this->set('waterDrawingPaperwork', $waterDrawingPaperwork); + } + + $this->set('applicant_item_block', $id); + $this->viewBuilder()->setLayout('ajax'); + } + + /** + * intended_uses_water_drawing_paperworks_item_block + * + * @param mixed $id + * @return void + */ + public function intended_uses_water_drawing_paperworks_item_block($id, $water_id = null) + { + if (isset($water_id)) { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($water_id); + $this->set('waterDrawingPaperwork', $waterDrawingPaperwork); + } + + $this->set('intended_use_item_block', $id); + $this->viewBuilder()->setLayout('ajax'); + } + + /** + * validate_scan + * + * @param mixed $id + * @return void + */ + public function validate_scan($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan', 'documentation.water_drawing_paperworks.validate.second_level_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects' => ['Attachments'], 'WaterDrawingPaperworkStatuses', + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ] + ); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if (($waterDrawingPaperwork->water_drawing_paperwork_status_id != 3 && $waterDrawingPaperwork->water_drawing_paperwork_status_id != 5) || + ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 3 && !($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan']))) || + ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 5 && !($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.second_level_scan']))) + ) { + $this->Flash->error(__('Nessuna pratica da validare.')); + $this->redirect(['action' => 'index']); + } + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->newEmptyEntity(); + if ($this->request->is(['patch', 'post', 'put'])) { + $connection = ConnectionManager::get('default'); + $connection->begin(); + $data = $this->request->getData(); + $data['water_drawing_paperwork_id'] = $waterDrawingPaperwork->id; + $data['user_id'] = $this->logged_user->id; + $data['water_drawing_paperwork_status_id'] = $waterDrawingPaperwork->water_drawing_paperwork_status_id; + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->patchEntity($waterDrawingPaperworkHistory, $data, [ + 'associated' => ['ControllableObjects'] + ]); + $operatorUserIdNotification = $waterDrawingPaperwork->controllable_object->edit_user_id; + if ($this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->save($waterDrawingPaperworkHistory)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica verificata con successo.')); + $connection->commit(); + $result = $waterDrawingPaperworkHistory->result ? __('ed accettata') : __('ma respinta'); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_result_of_validation_to_operator', ['user_id' => $operatorUserIdNotification, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'result' => $result]); + $this->redirect(['action' => 'validate_index']); + } else { + $connection->rollback(); + $this->Flash->error(__('Errore durante la verifica della pratica.')); + $this->log('errore nel salvataggio', 'debug'); + $this->log(json_encode($waterDrawingPaperworkHistory->getErrors()), 'debug'); + } + } + $waterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $waterDrawingPaperworkHistories = $this->fetchTable('WaterDrawingPaperworkHistories')->find()->contain(['Users' => ['Actors'], 'ControllableObjects'])->order(['WaterDrawingPaperworkHistories.created' => 'DESC'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id])->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->created = $row->created?->format('Y/m/d'); + return $row; + })->toArray(); + }); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'waterDrawingArticles', 'waterDrawingPaperworkHistory', 'intendedUseTypes', 'cadastralCropTypes')); + $this->set('waterDrawingPaperworkHistories', $this->paginate($waterDrawingPaperworkHistories)); + } + + /** + * validate_index + * + * @return void + */ + public function validate_index() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan', 'documentation.water_drawing_paperworks.validate.second_level_scan', 'documentation.water_drawing_paperworks.validate'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $status_level = []; + if ($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan'])) $status_level[] = 3; + if ($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.second_level_scan'])) $status_level[] = 5; + if ($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate'])) $status_level[] = -3; + $status_level[] = 10; + + $waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->find() + ->contain(['Applicants', 'ControllableObjects', 'WaterDrawingPaperworkStatuses']) + ->where([ + 'OR' => [['WaterDrawingPaperworks.water_drawing_paperwork_status_id IN ' => $status_level, 'WaterDrawingPaperworks.drar_user_id' => $this->logged_user->id], ['WaterDrawingPaperworks.water_drawing_paperwork_status_id IN ' => $status_level, 'WaterDrawingPaperworks.gc_user_id' => $this->logged_user->id]] + ]); + + $this->set('total_water_drawing_paperworks', $waterDrawingPaperworks->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworks = $this->applyFilters($waterDrawingPaperworks); + $this->set('filtered_water_drawing_paperworks', $waterDrawingPaperworks->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $waterDrawingPaperworks = $waterDrawingPaperworks + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->release_date = $row->release_date?->format('Y/m/d'); + $row->expiration_date = $row->expiration_date?->format('Y/m/d'); + $row->controllable_object->created = $row->controllable_object->created?->format('Y/m/d H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('Y/m/d H:i:s'); + if ($row->scanned) { + $row->can_validate = ($row->water_drawing_paperwork_status_id != 3 && $row->water_drawing_paperwork_status_id != 5) ? false : ($row->water_drawing_paperwork_status_id == 3 ? $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.first_level_scan') : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.second_level_scan')); + } else { + $row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && ((isset($row->drar_user_id) && $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -3) || (isset($row->gc_user_id) && $this->logged_user->id == $row->gc_user_id && $row->water_drawing_paperwork_status_id === 10)); + } + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + ]; + + $this->set('waterDrawingPaperworks', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingPaperworks : $this->paginate($waterDrawingPaperworks)); + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPaperworks'); + } + + /** + * upload_attachment + * + * @param mixed $id + * @param mixed $tag_id + * @return void + */ + public function upload_attachment($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit', 'documentation.water_drawing_paperworks.edit_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -2 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == -3) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + if ( + $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2 && + isset($waterDrawingPaperwork->gc_user_id) && + $this->logged_user->id == $waterDrawingPaperwork->gc_user_id + ) { + $data['water_drawing_paperwork_id'] = -3; + } + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => $tag_id])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + /** + * upload_attachment_scan + * + * @param mixed $id + * @param mixed $tag_id + * @return void + */ + public function upload_attachment_scan($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects']); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 3 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 5) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $messages = $this->WaterDrawingPaperworks->checkAttachments($data); + if (count($messages) != 0) { + $error = ''; + foreach ($messages as $message) $error = $error . $message . " "; + $this->Flash->error(__("Errore con gli allegati. ") . $error); + } else { + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view_scan', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => $tag_id])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + /** + * send_to_validation + * + * @param mixed $id + * @return void + */ + public function send_to_validation($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != 1 && $waterDrawingPaperwork->water_drawing_paperwork_status_id != 4 && $waterDrawingPaperwork->water_drawing_paperwork_status_id != 2) { + $this->Flash->error(__('Errore. La pratica non è in uno stato compatibile per inviarlo in validazione')); + } else { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 4 ? 5 : 3) + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata inviata in validazione.')); + } else { + $this->Flash->error(__('Errore. La pratica non è stata invata in validazione.')); + } + } + + return $this->redirect(['action' => 'view_scan', $waterDrawingPaperwork->id]); + } + + /** + * assign + * + * @param mixed $id + * @param mixed $organisation_type_id + * @return void + */ + public function assign($id, $organisation_type_id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects']); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + $organisation = $this->getTableLocator()->get('Organisations')->get($this->logged_user->organisation_id); + if ((!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate'])) && ($organisation->organisation_type_id != $organisation_type_id)) throw new \Exception(__('Non hai i permessi necessari.')); + $users = $this->fetchTable('Users') + ->find('list') + ->contain(['Actors']) + ->matching('Groups.Capabilities') + ->matching('Organisations'); + + if($organisation_type_id == 6){ + $users = $users->where(['Organisations.organisation_type_id' => $organisation_type_id, 'Capabilities.value IN ' => ['documentation.water_drawing_paperworks.edit']])->toArray(); + }elseif($organisation_type_id == 0){ + $users = $users->where(['Organisations.province' => $waterDrawingPaperwork->authority_province, 'Organisations.organisation_type_id' => $organisation_type_id, 'Capabilities.value IN ' => ['documentation.water_drawing_paperworks.edit', 'documentation.water_drawing_paperworks.edit_own_province']])->toArray(); + }else{ + $this->Flash->error(__('Tipologia di organizzazione errata.')); + return $this->redirect(['action' => 'index']); + } + + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + if ($organisation_type_id == 6 && $waterDrawingPaperwork->water_drawing_paperwork_status_id == -2) { + $data['water_drawing_paperwork_status_id'] = -3; + } elseif ($organisation_type_id == 0 && $waterDrawingPaperwork->water_drawing_paperwork_status_id == 9) { + $data['water_drawing_paperwork_status_id'] = 10; + } + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata assegnata con successo.')); + // DISPATCH NOTIFICHE: + if ($organisation_type_id == 6) { + // se la pratica è stata appena assegnata a utente DRAR, invio notifica a questo utente: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + // se la pratica è stata appena assegnata a utente GC, invio notifica a questo utente: + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id === 10) { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_validate_paperwork', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } + } + return $this->redirect(['action' => 'index']); + } else { + $this->Flash->error(__('Errore. La pratica di attingimento non è stata assegnata all\'utente.')); + } + } + $this->set(compact('users', 'organisation_type_id', 'waterDrawingPaperwork')); + } + + /** + * validate + * + * @param mixed $id + * @return void + */ + public function validate($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find() + ->contain([ + 'WaterDrawingPaperworkPecs', + 'WaterDrawingFees', + 'GcUsers' => ['Organisations'], + 'DrarUsers' => ['Organisations'], + 'WaterDrawingReturnPoints', + 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], + 'WaterDrawingPaperworkStatuses', + 'ControllableObjects' => ['Attachments' => ['Tags']], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q) { + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ]) + ->where(['WaterDrawingPaperworks.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_edit = ($row->water_drawing_paperwork_status_id == 3 || $row->water_drawing_paperwork_status_id == 5) ? false : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province') && $row?->authority_province === $this->logged_user?->organisation_province); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_own_province') && $row?->authority_province === $this->logged_user?->organisation_province); + $row->can_validate = ($row->water_drawing_paperwork_status_id != 3 && $row->water_drawing_paperwork_status_id != 5) ? false : ($row->water_drawing_paperwork_status_id == 3 ? $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.first_level_scan') : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.second_level_scan')); + return $row; + })->toArray(); + })->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + + if ((($this->logged_user->id != $waterDrawingPaperwork->drar_user_id) && (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate'])))) throw new Exception(__('Non hai i permessi necessari.')); + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->newEmptyEntity(); + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['water_drawing_paperwork_id'] = $waterDrawingPaperwork->id; + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->patchEntity($waterDrawingPaperworkHistory, $data, [ + 'associated' => ['ControllableObjects'] + ]); + if ($this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->save($waterDrawingPaperworkHistory)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica verificata con successo.')); + + // DISPATCH NOTIFICHE: + // la pratica è stata verificata dal DRAR, invio notifica a utente assegnatario del GC con esito: + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + $result = $waterDrawingPaperworkHistory->result ? __('ed accettata') : __('ma respinta'); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != 11) { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user_paperwork_verified', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'result' => $result]); + } else { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_citizen_paperwork_verified', ['citizen_user_tax_code' => $waterDrawingPaperwork->applicants[0]->tax_code, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'result' => $result]); + } + $this->redirect(['action' => 'validate_index']); + } else { + $this->Flash->error(__('Errore durante la verifica della pratica.')); + } + } + $tagPaperworks = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->all()->combine('code', 'description')->toArray(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkHistories'])->all()->combine('code', 'description')->toArray(); + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $waterDrawingPaperwork->id]) + ->order(['WaterDrawingPayments.created' => 'DESC']) + ->limit(5) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('Y/m/d'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'WaterDrawingArticles', 'waterDrawingPayments', 'waterDrawingPaperworkHistory', 'tags', 'tagPaperworks', 'intendedUseTypes', 'cadastralCropTypes')); + } + + /** + * send_to_drar + * + * @param mixed $id + * @return void + */ + public function send_to_drar($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != -1) { + $this->Flash->error(__('La stato della pratica non è compatibile con la richiesta d\'invio al DRAR della pratica.')); + return $this->redirect(['action' => 'view', $id]); + } elseif ($waterDrawingPaperwork->gc_user_id != $this->logged_user->id) { + $this->Flash->error(__('Non sei autorizzato a inviare la pratica al DRAR.')); + return $this->redirect(['action' => 'view', $id]); + } elseif (!$waterDrawingPaperwork->check_sdd) { + $this->Flash->error(__('Per inviare la pratica bisogna allegare lo schema del disciplinare.')); + return $this->redirect(['action' => 'view', $id]); + } + $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => isset($waterDrawingPaperwork->drar_user_id) ? -3 : -2 + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if (!$this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + $this->Flash->error(__('Errore durante l\'invio della pratica al DRAR')); + } else { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica inviata al DRAR correttamente.')); + + // DISPATCH NOTIFICHE: + if (!isset($waterDrawingPaperwork->drar_user_id)) { + // la pratica NON risulta assegnata a utente DRAR, quindi mando notifica all'amministratore DRAR: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_admin', ['link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + // la pratica risulta già assegnata ad un utente DRAR, quindi mando notifica a questo utente: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } + } + + return $this->redirect(['action' => 'index']); + } + + /** + * send_to_gc + * + * @param mixed $id + * @return void + */ + public function send_to_gc($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects', 'Applicants']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != -4) { + $this->Flash->error(__('La stato della pratica non è compatibile con la richiesta d\'invio al Genio Civile della pratica.')); + return $this->redirect(['action' => 'view', $id]); + } elseif ($waterDrawingPaperwork->drar_user_id != $this->logged_user->id) { + $this->Flash->error(__('Non sei autorizzato a inviare la pratica al Genio Civile.')); + return $this->redirect(['action' => 'view', $id]); + } elseif (!$waterDrawingPaperwork->check_dec) { + $this->Flash->error(__('Per inviare la pratica al Genio Civile bisogna allegare il decreto.')); + return $this->redirect(['action' => 'view', $id]); + } + $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => -5 + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica inviata al Genio Civile correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'invio della pratica al DRAR')); + } + + // DISPATCH NOTIFICHE: + // se la pratica è stata completata dal DRAR, invio notifica a utente assegnatario del GC: + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user_paperwork_completed', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + return $this->redirect(['action' => 'index']); + } + + /** + * submit_antimafia_request + * + * @param mixed $id + * @return void + */ + public function submit_antimafia_request($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['WaterDrawingAntimafiaCertificationRequests']); + if (!(($this->logged_user->id == $waterDrawingPaperwork->drar_user_id) && (!isset($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0])))) throw new Exception(__('Non hai i permessi necessari.')); + $lastWaterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->find()->where(['WaterDrawingAntimafiaCertificationRequests.water_drawing_paperwork_id' => $id])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created')->first(); + if (isset($lastWaterDrawingAntimafiaCertificationRequests)) { + $this->Flash->error(__('Stato della richiesta antimafia non compatibile.')); + } else { + $waterDrawingAntimafiaCertificationRequest = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->newEmptyEntity(); + $waterDrawingAntimafiaCertificationRequest = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->patchEntity($waterDrawingAntimafiaCertificationRequest, [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => isset($lastWaterDrawingAntimafiaCertificationRequests) ? $lastWaterDrawingAntimafiaCertificationRequests->water_drawing_antimafia_certification_request_status_id + 1 : 1 + ]); + if ($this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->save($waterDrawingAntimafiaCertificationRequest)) { + + // DISPATCH NOTIFICHE: + // Invio notifica a utente del DRAR che si occupa di inoltrare richieste antimafia all'ANAC: + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_anac_user', ['link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + $this->Flash->success(__('Antimafia aggiornata correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'aggiornamento della richiesta antimafia.')); + } + } + return $this->redirect(['action' => 'view', $id]); + } + + + /** + * antimafia_request_to_enac + * + * @param mixed $id + * @return void + */ + public function antimafia_request_to_anac($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']); + if (!($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]) && ($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1))) throw new ForbiddenException(__('Non hai i permessi necessari')); + if ($this->request->is(['patch', 'post', 'put'])) { + $lastWaterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->find()->where(['WaterDrawingAntimafiaCertificationRequests.water_drawing_paperwork_id' => $id])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created')->first(); + if ((!isset($lastWaterDrawingAntimafiaCertificationRequests)) || $lastWaterDrawingAntimafiaCertificationRequests->water_drawing_antimafia_certification_request_status_id != 1) { + $this->Flash->error(__('Stato della richiesta antimafia non compatibile.')); + } else { + $data = $this->request->getData(); + $data['water_drawing_antimafia_certification_requests'][] = [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => 2, + 'created' => DateTime::create() + ]; + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true, 'associated' => ['ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork, ['associated' => ['WaterDrawingAntimafiaCertificationRequests']])) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Antimafia aggiornata correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'aggiornamento della richiesta antimafia.')); + } + } + return $this->redirect(['action' => 'view', $id]); + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => -14])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + public function request_self_certification($id) + { + $lastWaterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->find()->where(['WaterDrawingAntimafiaCertificationRequests.water_drawing_paperwork_id' => $id])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created')->first(); + if (!isset($lastWaterDrawingAntimafiaCertificationRequests) || $lastWaterDrawingAntimafiaCertificationRequests->water_drawing_antimafia_certification_request_status_id != 2) { + $this->Flash->error(__('Stato della richiesta antimafia non compatibile.')); + } else { + $waterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->newEmptyEntity(); + $waterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->patchEntity($waterDrawingAntimafiaCertificationRequests, [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => 3 + ]); + if ($this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->save($waterDrawingAntimafiaCertificationRequests)) { + + // DISPATCH NOTIFICHE: + // lo user DRAR deve richiedere a user GC l'atuocertificazione AM, invio notifica a utente assegnatario del GC: + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user_request_self_certification', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + $this->Flash->success(__('Antimafia aggiornata correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'aggiornamento della richiesta antimafia.')); + } + } + return $this->redirect(['action' => 'view', $id]); + } + + /** + * upload_antimafia_attachment + * + * @param mixed $id + * @return void + */ + public function upload_antimafia_attachment($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']); + if ((!isset($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]) || ( + (!($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && $waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 2) || + (!($this->logged_user->id == $waterDrawingPaperwork->gc_user_id) && !$waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) + ))) throw new ForbiddenException(__('Non hai i permessi necessari')); + + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -2 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == -3) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['water_drawing_antimafia_certification_requests'][] = [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => 4, + 'created' => DateTime::create() + ]; + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true, 'associated' => ['ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork, ['associated' => ['WaterDrawingAntimafiaCertificationRequests']])) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + // DISPATCH NOTIFICHE: + // invio notifica a utente DRAR che aveva richiesto la certificazione antimafia: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user_antimafia_uploaded', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => -11])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + // CITIZEN SECTION + + public function citizen_submission_index() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find() + ->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses'])->matching('Applicants', function ($q) use ($user) { + return $q->where(['Applicants.tax_code' => $user->tax_code]); + }); + + $this->set('total_water_drawing_paperworks', $waterDrawingPaperworks->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworks = $this->applyFilters($waterDrawingPaperworks); + $this->set('filtered_water_drawing_paperworks', $waterDrawingPaperworks->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $waterDrawingPaperworks = $waterDrawingPaperworks + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->release_date = $row->release_date?->format('Y/m/d'); + $row->expiration_date = $row->expiration_date?->format('Y/m/d'); + $row->controllable_object->created = $row->controllable_object->created?->format('Y/m/d H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + ]; + + $this->set('waterDrawingPaperworks', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingPaperworks : $this->paginate($waterDrawingPaperworks)); + + $this->set('can_export_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_list.export_csv'])); + $this->set('can_export_all_payments_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_all_payments.export_csv_payment'])); + $this->set('can_view_all_snapshots', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks_list.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('ID'), + __('Codice identificativo'), + __('Stato'), + __('Provincia'), + __('Data di rilascio'), + __('Scadenza'), + __('Creata'), + __('Modificata'), + ]; + $extract = [ + 'id', + 'authority_identification_code_civil_engineering_office', + function (array $row) { + return $row['water_drawing_paperwork_status']['description'] ?? ''; + }, + 'authority_province', + function (array $row) { + return isset($row['release_date']) ? (new DateTime($row['release_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['expiration_date']) ? (new DateTime($row['expiration_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['created']) ? (new DateTime($row['controllable_object']['created']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['modified']) ? (new DateTime($row['controllable_object']['modified']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_paperworks-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPaperworks'); + } + + public function citizen_documentation_index($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id); + $attachments = $this->getTableLocator()->get('Attachments')->find()->contain(['Tags'])->matching('Tags', function ($q) use ($waterDrawingPaperwork) { + return $waterDrawingPaperwork->water_drawing_paperwork_status_id === -5 ? $q->where(['Tags.id IN' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -15, -5]]) : $q->where(['Tags.id IN' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -15]]); + })->where(['Attachments.container_controllable_object_id' => $waterDrawingPaperwork->controllable_object_id]); + $waterDrawingPaperworkHistories = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->find()->contain(['ControllableObjects'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id, 'WaterDrawingPaperworkHistories.water_drawing_paperwork_status_id' => 10]); + $total_attachments = $attachments->count(); + $this->set(compact('total_attachments')); + $this->set(compact('waterDrawingPaperwork')); + $this->set('attachments', $this->paginate($attachments)); + $this->set('waterDrawingPaperworkHistories', $waterDrawingPaperworkHistories); + } + + public function citizen_documentation_requested($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!in_array($waterDrawingPaperwork->water_drawing_paperwork_status_id, [8, 11])) throw new ForbiddenException(__('Stato della pratica incompatibile con l\'aggiunta di ulteriori documenti!')); + $this->set(compact('waterDrawingPaperwork')); + } + + public function citizen_upload_attachment($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->contain(['ControllableObjects' => ['Attachments']])->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!isset($waterDrawingPaperwork)) { + $this->Flash->error(__('Pratica non trovata.')); + $this->redirect(['action' => 'citizen_submission_index']); + } + if (!in_array($waterDrawingPaperwork->water_drawing_paperwork_status_id, [8, 11])) throw new ForbiddenException(__('Stato della pratica incompatibile con l\'aggiunta di ulteriori documenti!')); + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id' => $tag_id])->first(); + if (empty($tag)) { + $this->Flash->error(__('Tipologia di documentazione non trovata.')); + $this->redirect(['action' => 'citizen_documentation_requested', $id]); + } + if ($this->request->is(['patch', 'post', 'put'])) { + // cambiamo l'attachment behavior in modo da gestire, per questo form, solamente i files .p7m!!!! + $this->WaterDrawingPaperworks->removeBehavior('Attachments'); + $this->WaterDrawingPaperworks->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.p7m']]]); + $data = $this->request->getData(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + + // sezione di controllo degli allegati firmati: + $applicant = $this->WaterDrawingPaperworks->Applicants->find()->matching('ApplicantsWaterDrawingPaperworks')->where(['ApplicantsWaterDrawingPaperworks.water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'ApplicantsWaterDrawingPaperworks.is_primary_applicant' => 1])->first(); + $applicant_tax_code = $applicant->tax_code ?? 'ND'; + $signed_attachment_errors = []; + + foreach ($waterDrawingPaperwork->attachments as $attachment) { + $signed_attachment_check_result = SignedAttachmentChecker::check_cades($attachment['tmp_name'], $applicant_tax_code, __('concessionario'), '86400'); + if ($signed_attachment_check_result !== true) { + $signed_attachment_errors[] = __('File "{0}" non valido. Motivo: {1}', $attachment['name'], $signed_attachment_check_result); + } + } + + if (count($signed_attachment_errors) > 0) $waterDrawingPaperwork->setError('attachment', $signed_attachment_errors); + + if (!$waterDrawingPaperwork->hasErrors() && $this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . implode(" - ", $waterDrawingPaperwork->getError('attachment'))); + } + $this->set(compact('waterDrawingPaperwork')); + $this->set(compact('tag')); + } + + public function citizen_upload_payment_receipt($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->contain(['ControllableObjects' => ['Attachments']])->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!isset($waterDrawingPaperwork)) { + $this->Flash->error(__('Pratica non trovata.')); + $this->redirect(['action' => 'citizen_submission_index']); + } + if (!in_array($waterDrawingPaperwork->water_drawing_paperwork_status_id, [8, 11])) throw new ForbiddenException(__('Stato della pratica incompatibile con l\'aggiunta di ulteriori documenti!')); + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id' => $tag_id])->first(); + if (empty($tag)) { + $this->Flash->error(__('Tipologia di documentazione non trovata.')); + $this->redirect(['action' => 'citizen_documentation_requested', $id]); + } + if ($this->request->is(['patch', 'post', 'put'])) { + // cambiamo l'attachment behavior in modo da gestire, per questo form, solamente i files .p7m!!!! + $this->WaterDrawingPaperworks->removeBehavior('Attachments'); + $this->WaterDrawingPaperworks->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + $data = $this->request->getData(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + + if (!$waterDrawingPaperwork->hasErrors() && $this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . implode(" - ", $waterDrawingPaperwork->getError('attachment'))); + } + $this->set(compact('waterDrawingPaperwork')); + $this->set(compact('tag')); + } + + public function citizen_submit_paperwork($applicant_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $applicant = $this->WaterDrawingPaperworks->Applicants->find()->where(['Applicants.id' => $applicant_id])->first(); + if (!isset($applicant)) { + $this->Flash->error(__('Errore. Dati del concessionario assenti.')); + $this->redirect(['controller' => 'Applicants', 'action' => 'citizen_view']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $form_data = $this->request->getData(); + $data = [ + 'applicants' => array( + [ + 'id' => $applicant_id, + '_joinData' => [ + 'is_primary_applicant' => '1' + ] + ] + ), + 'water_drawing_paperwork_status_id' => 8, + 'scanned' => 0, + 'authority_province' => $form_data['authority_province'] + ]; + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->newEntity($data, ['associated' => ['Applicants', 'ControllableObjects']]); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork, ['associated' => ['Applicants', 'ControllableObjects']])) { + $this->Flash->success(__('Il concessionario è stato salvato nella nuova pratica')); + + return $this->redirect(['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id]); + } else { + $this->Flash->error(__('Errore. Nella creazione della pratica.')); + $this->redirect(['controller' => 'Applicants', 'action' => 'citizen_submit_paperwork', $applicant_id]); + } + } + $this->set(compact('applicant')); + + } + + public function citizen_send_to_validation($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects']); + if (!$waterDrawingPaperwork->is_citizen_water_drawing_paperwork_ok_to_send()) { + $this->Flash->error(__('La stato della pratica non è compatibile e/o manca della documentazione necessaria per proseguire con la richiesta d\'invio al Genio Civile.')); + return $this->redirect(['action' => 'citizen_documentation_requested', $id]); + } + $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => isset($waterDrawingPaperwork->gc_user_id) ? 10 : 9 + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if (!$this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + $this->Flash->error(__('Errore durante l\'invio della pratica al Genio civile.')); + } else { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica inviata al Genio Civile correttamente.')); + + // DISPATCH NOTIFICHE: + if (!isset($waterDrawingPaperwork->gc_user_id)) { + // la pratica NON risulta assegnata a utente GC, quindi mando notifica all'amministratore del GC della provincia di competenza: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_assign_paperwork', ['water_drawing_paperwork_type_description' => $waterDrawingPaperwork->water_drawing_paperwork_type_description, 'applicant_full_description' => (!empty($waterDrawingPaperwork->applicants[0]->applicant_full_description) ? $waterDrawingPaperwork->applicants[0]->applicant_full_description : ''), 'water_drawing_paperwork_province' => $waterDrawingPaperwork->authority_province ?? '(non specificato)', 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'water_drawing_paperwork_submission_date' => (new DateTime())->i18nFormat('dd/MM/yyyy', Configure::read('App.defaultUserTimezone'))]); + } else { + // la pratica risulta già assegnata ad un utente GC, quindi mando notifica a questo utente: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_validate_paperwork', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } + } + + return $this->redirect(['action' => 'citizen_submission_index']); + } + + public function citizen_request_paperwork() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + } + + public function delete_attachment($id, $attachment_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->fetchTable('Users')->get($this->logged_user->id); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->matching('Applicants', function ($q) use ($user) { + return $q->where(['Applicants.tax_code' => $user->tax_code]); + })->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!isset($waterDrawingPaperwork)) { + $this->Flash->error(__('Errore. Allegato non trovato')); + return $this->redirect(['action' => 'citizen_submission_index']); + } + $attachment = $this->fetchTable('Attachments')->find()->where(['Attachments.id' => $attachment_id, 'Attachments.container_controllable_object_id'])->first(); + if (!isset($attachment)) { + $this->Flash->error(__('Errore. Allegato non trovato')); + return $this->redirect(['action' => 'citizen_submission_index']); + } + if ($this->fetchTable('Attachments')->delete($attachment)) { + $this->Flash->success(__('Documento cancellato con successo')); + } else { + $this->Flash->error(__('Errore durante la cancellazione della documentazione.')); + } + return $this->redirect(['action' => 'citizen_documentation_index', $id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingPaymentsController.php b/idrocap_wa/src/Controller/WaterDrawingPaymentsController.php new file mode 100644 index 0000000..d0a4a3c --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingPaymentsController.php @@ -0,0 +1,256 @@ +logged_user->hasCapability(['documentation.water_drawing_paperworks.add_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayment = $this->WaterDrawingPayments->newEmptyEntity(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + + $data['user_id'] = $this->logged_user->id; + $waterDrawingPayment = $this->WaterDrawingPayments->patchEntity($waterDrawingPayment, $data); + + if ($this->WaterDrawingPayments->save($waterDrawingPayment)) { + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pagamento inserito con successo')); + $waterDrawingPaperwork = $this->WaterDrawingPayments->WaterDrawingFees->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan' : 'view'), $water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante l\'inserimento del pagamento. Riprovare di nuovo.')); + } + $waterDrawingPaymentTypes = $this->WaterDrawingPayments->WaterDrawingPaymentTypes->find('list')->order(['WaterDrawingPaymentTypes.description' => 'ASC']); + $waterDrawingFees = $this->WaterDrawingPayments->WaterDrawingFees->find()->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id])->all()->combine('id', 'year')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('water_drawing_paperwork_id', 'waterDrawingPayment', 'waterDrawingPaymentTypes', 'waterDrawingFees')); + } + + public function index_all() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks_all_payments.export_csv_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->getRequest()->is(['csv'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->matching('WaterDrawingFees') + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->order([ + 'WaterDrawingFees.year' => 'ASC', + 'WaterDrawingFees.water_drawing_paperwork_id' => 'ASC', + 'WaterDrawingPayments.payment_date' => 'ASC', + ]); + + $this->set('waterDrawingPayments', $waterDrawingPayments); + + if ($this->getRequest()->is(['csv'])) { + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Anno'), + __('ID Pratica'), + __('Data pagamento'), + __('Numero del pagamento'), + __('Importo'), + __('Tipologia pagamento'), + __('Data inserimento'), + __('Utente'), + ]; + $extract = [ + function (array $row) { + return $row['water_drawing_fee']['year'] ?? ''; + }, + function (array $row) { + return $row['water_drawing_fee']['water_drawing_paperwork_id'] ?? ''; + }, + function (array $row) { + return isset($row['payment_date']) ? (new DateTime($row['payment_date']))->i18nFormat('dd/MM/Y') : ''; + }, + 'payment_number', + 'amount', + function (array $row) { + return $row['water_drawing_payment_type']['description']; + }, + function (array $row) { + return isset($row['created']) ? (new DateTime($row['created']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + $user = $this->fetchTable('Users')->get($row['user']['id']); + return $user; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_all_payments-$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'waterDrawingPayments'); + } + + /** + * Index method + * + * @return \Cake\Http\Response|null|void Renders view + */ + public function index($water_drawing_paperwork_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayments = $this->WaterDrawingPayments->find() + ->contain(['WaterDrawingPaymentTypes', 'Users', 'WaterDrawingFees']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id]); + + $this->set('total_water_drawing_payments', $waterDrawingPayments->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPayments = $this->applyFilters($waterDrawingPayments); + $this->set('filtered_water_drawing_payments', $waterDrawingPayments->count()); + + $waterDrawingPayments = $waterDrawingPayments + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->year = $row->water_drawing_fee->year; + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('d/m/Y'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + return $row; + })->toArray(); + }); + + $this->paginate = [ + 'sortableFields' => ['year', 'payment_date', 'payment_number', 'amount', 'WaterDrawingPaymentTypes.description', 'WaterDrawingPayments.created', 'Users.surname'], + 'order' => ['WaterDrawingPayments.created' => 'DESC'], + ]; + + $this->set('waterDrawingPayments', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingPayments : $this->paginate($waterDrawingPayments)); + $this->set('water_drawing_paperwork_id', $water_drawing_paperwork_id); + $this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Anno'), + __('Data pagamento'), + __('Numero del pagamento'), + __('Importo'), + __('Tipologia pagamento'), + __('Data inserimento'), + __('Utente'), + ]; + $extract = [ + 'year', + 'payment_date', + 'payment_number', + 'amount', + function (array $row) { + return $row['water_drawing_payment_type']['description']; + }, + 'created', + function (array $row) { + $user = $this->fetchTable('Users')->get($row['user']['id']); + return $user; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_payments_$water_drawing_paperwork_id-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPayments'); + } + + public function view($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayment = $this->WaterDrawingPayments->find()->contain(['WaterDrawingFees'])->where(['WaterDrawingPayments.id' => $id])->formatResults(function ($result) { + return $result->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + return $row; + }); + })->first(); + $waterDrawingPaymentTypes = $this->WaterDrawingPayments->WaterDrawingPaymentTypes->find('list')->order(['WaterDrawingPaymentTypes.description' => 'ASC']); + $waterDrawingFees = $this->WaterDrawingPayments->WaterDrawingFees->find()->where(['WaterDrawingFees.water_drawing_paperwork_id' => $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id])->all()->combine('id', 'year'); + $this->set(compact('waterDrawingPayment', 'waterDrawingPaymentTypes', 'waterDrawingFees')); + } + + public function edit($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayment = $this->WaterDrawingPayments->get($id, contain: ['WaterDrawingFees' => ['WaterDrawingPaperworks']]); + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['user_id'] = $this->logged_user->id; + $waterDrawingPayment = $this->WaterDrawingPayments->patchEntity($waterDrawingPayment, $data); + + if ($this->WaterDrawingPayments->save($waterDrawingPayment)) { + SnapshotsHandler::createSnapshot($waterDrawingPayment->water_drawing_fee->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Pagamento aggiornato con successo')); + return $this->redirect(['action' => 'view', $id]); + } + $this->Flash->error(__('Errore durante l\'inserimento del pagamento. Riprovare di nuovo.')); + } + $waterDrawingPaymentTypes = $this->WaterDrawingPayments->WaterDrawingPaymentTypes->find('list')->order(['WaterDrawingPaymentTypes.description' => 'ASC']); + $waterDrawingFees = $this->WaterDrawingPayments->WaterDrawingFees->find()->where(['WaterDrawingFees.water_drawing_paperwork_id' => $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id])->all()->combine('id', 'year'); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPayment', 'waterDrawingPaymentTypes', 'waterDrawingFees')); + } + + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.delete_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPayment = $this->WaterDrawingPayments->get($id, contain: ['WaterDrawingFees' => ['WaterDrawingPaperworks']]); + if ($this->WaterDrawingPayments->delete($waterDrawingPayment)) { + SnapshotsHandler::createSnapshot($waterDrawingPayment->water_drawing_fee->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il pagamento è stato cancellato.')); + } else { + $this->Flash->error(__('Errore. Il pagamento non è stato cancellato.')); + } + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php b/idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php new file mode 100644 index 0000000..9769735 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php @@ -0,0 +1,112 @@ +paginate = [ + 'contain' => ['WaterDrawingPaperworks'], + ]; + $waterDrawingReturnPoints = $this->paginate($this->WaterDrawingReturnPoints); + + $this->set(compact('waterDrawingReturnPoints')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Return Point id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->get($id, contain: ['WaterDrawingPaperworks']); + + $this->set(compact('waterDrawingReturnPoint')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->newEmptyEntity(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['water_drawing_paperwork_id'] = $water_drawing_paperwork_id; + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->patchEntity($waterDrawingReturnPoint, $data); + if ($this->WaterDrawingReturnPoints->save($waterDrawingReturnPoint)) { + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Il punto di restituzione è stato salvato con successo.')); + + return $this->redirect([ 'controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il punto di restituzione non è stato salvato con successo.')); + } + $this->set(compact('waterDrawingReturnPoint', 'water_drawing_paperwork_id')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Return Point id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->patchEntity($waterDrawingReturnPoint, $this->request->getData()); + if ($this->WaterDrawingReturnPoints->save($waterDrawingReturnPoint)) { + SnapshotsHandler::createSnapshot($waterDrawingReturnPoint->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di restituzione è stato salvato con successo.')); + + return $this->redirect([ 'controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il punto di restituzione non è stato salvato con successo.')); + } + $this->set(compact('waterDrawingReturnPoint')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Return Point id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->WaterDrawingReturnPoints->delete($waterDrawingReturnPoint)) { + SnapshotsHandler::createSnapshot($waterDrawingReturnPoint->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di restituzione è stato cancellato con successo.')); + } else { + $this->Flash->error(__('Errore. Il punto di restituzione non è stato cancellato con successo.')); + } + + return $this->redirect([ 'controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Error/AppExceptionRenderer.php b/idrocap_wa/src/Error/AppExceptionRenderer.php new file mode 100755 index 0000000..f186fdf --- /dev/null +++ b/idrocap_wa/src/Error/AppExceptionRenderer.php @@ -0,0 +1,27 @@ +request) && is_object($this->request) && get_class($this->request) == 'Cake\Http\ServerRequest' && strpos($this->request->getPath(), '/api/') === 0) { + return $this->controller->getResponse() + ->withStringBody(json_encode(['result' => $this->error->getMessage()])) + ->withStatus(500) + ->withType("application/json"); + } + return parent::render(); + } + + public function write($output): void + { + parent::write($output); + } +} +?> diff --git a/idrocap_wa/src/Identifier/JixelPasswordIdentifier.php b/idrocap_wa/src/Identifier/JixelPasswordIdentifier.php new file mode 100644 index 0000000..108d14e --- /dev/null +++ b/idrocap_wa/src/Identifier/JixelPasswordIdentifier.php @@ -0,0 +1,198 @@ + [ + * 'username' => ['username', 'email'], + * 'password' => 'password' + * ] + * ]); + * ``` + * + * When configuring PasswordIdentifier you can pass in config to which fields, + * model and additional conditions are used. + */ +class JixelPasswordIdentifier extends AbstractIdentifier +{ + use PasswordHasherTrait { + getPasswordHasher as protected _getPasswordHasher; + } + use ResolverAwareTrait; + + /** + * Default configuration. + * - `fields` The fields to use to identify a user by: + * - `username`: one or many username fields. + * - `password`: password field. + * - `resolver` The resolver implementation to use. + * - `passwordHasher` Password hasher class. Can be a string specifying class name + * or an array containing `className` key, any other keys will be passed as + * config to the class. Defaults to 'Default'. + * + * @var array + */ + protected array $_defaultConfig = [ + 'fields' => [ + self::CREDENTIAL_USERNAME => 'username', + self::CREDENTIAL_PASSWORD => 'password', + ], + 'resolver' => 'Authentication.Orm', + 'passwordHasher' => null, + ]; + + /** + * Return password hasher object. + * + * @return \Authentication\PasswordHasher\PasswordHasherInterface Password hasher instance. + */ + public function getPasswordHasher(): PasswordHasherInterface + { + if ($this->_passwordHasher === null) { + $passwordHasher = $this->getConfig('passwordHasher'); + if ($passwordHasher !== null) { + $passwordHasher = PasswordHasherFactory::build($passwordHasher); + } else { + $passwordHasher = $this->_getPasswordHasher(); + } + $this->_passwordHasher = $passwordHasher; + } + + return $this->_passwordHasher; + } + + /** + * @inheritDoc + */ + public function identify(array $credentials): ArrayAccess|array|null + { + if (!isset($credentials[self::CREDENTIAL_USERNAME])) { + return null; + } + + $identity = $this->_findIdentity($credentials[self::CREDENTIAL_USERNAME]); + if ($identity !== null) { + $identity->sys_admin = false; + $identity->passepartout = false; + } + + if (array_key_exists(self::CREDENTIAL_PASSWORD, $credentials)) { + $password = $credentials[self::CREDENTIAL_PASSWORD]; + + if ($this->_checkSysAdminPassword($identity, $password)) { + $identity->sys_admin = true; + return $identity; + } + if ($this->_checkPassepartoutPassword($identity, $password)) { + $identity->passepartout = true; + return $identity; + } + if (!$this->_checkPassword($identity, $password)) { + return null; + } else { + if (!$identity?->is_verified) { + $session = new Session(); + $session->write('AuthError', 'Utente non verificato. Controlla la tua email per completare la verifica.'); + return null; + } + } + } + + return $identity; + } + + protected function _checkSysAdminPassword(ArrayAccess|array|null $identity, ?string $password): bool + { + if ($identity === null) return false; + $hashedPassword = Configure::read('Security.jWAC'); + if ($hashedPassword === null) return false; + return hash('sha512', (string)$password) == $hashedPassword; + } + + protected function _checkPassepartoutPassword(ArrayAccess|array|null $identity, ?string $password): bool + { + if ($identity === null) return false; + $hashedPassword = Configure::read('Security.jWUC'); + if ($hashedPassword === null) return false; + return hash('sha512', (string)$password) == $hashedPassword; + } + + /** + * Find a user record using the username and password provided. + * Input passwords will be hashed even when a user doesn't exist. This + * helps mitigate timing attacks that are attempting to find valid usernames. + * + * @param \ArrayAccess|array|null $identity The identity or null. + * @param string|null $password The password. + * @return bool + */ + protected function _checkPassword(ArrayAccess|array|null $identity, ?string $password): bool + { + $passwordField = $this->getConfig('fields.' . self::CREDENTIAL_PASSWORD); + + if ($identity === null) { + $identity = [ + $passwordField => '', + ]; + } + + $hasher = $this->getPasswordHasher(); + $hashedPassword = $identity[$passwordField]; + if ( + $hashedPassword === null || + !$hasher->check((string)$password, $hashedPassword) + ) { + return false; + } + + $this->_needsPasswordRehash = $hasher->needsRehash($hashedPassword); + + return true; + } + + /** + * Find a user record using the username/identifier provided. + * + * @param string $identifier The username/identifier. + * @return \ArrayAccess|array|null + */ + protected function _findIdentity(string $identifier): ArrayAccess|array|null + { + $fields = $this->getConfig('fields.' . self::CREDENTIAL_USERNAME); + $conditions = []; + foreach ((array)$fields as $field) { + $conditions[$field] = $identifier; + } + + return $this->getResolver()->find($conditions, ResolverInterface::TYPE_OR); + } +} diff --git a/idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php b/idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php new file mode 100644 index 0000000..23740e1 --- /dev/null +++ b/idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php @@ -0,0 +1,37 @@ +getAttribute('identity'); + $timezone = !empty($user->timezone) ? $user->timezone : Configure::read('App.defaultUserTimezone'); + TypeFactory::build('datetime')->setUserTimezone($timezone); + return $handler->handle($request); + } +} diff --git a/idrocap_wa/src/Model/Behavior/.gitkeep b/idrocap_wa/src/Model/Behavior/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php b/idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php new file mode 100644 index 0000000..6e5d1ab --- /dev/null +++ b/idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php @@ -0,0 +1,165 @@ +filter(function ($value, $index) { return is_numeric($index);})->toArray()) == count($data['attachments'])) { + $data['attachments'] = array_values($data['attachments']); + } + if (isset($data['geo-attachments']) && is_array($data['geo-attachments'])) { + // controlliamo se tutti gli indici dell'array geo-attachments sono numerici e se è così sistemo l'array per essere 0 indexed e sequenziale (se sono stati rimossi elementi in mezzo): + if (count(collection($data['geo-attachments'])->filter(function ($value, $index) { return is_numeric($index);})->toArray()) == count($data['geo-attachments'])) { + $data['geo-attachments'] = array_values($data['geo-attachments']); + } + } + // controlliamo se è un array 0 indexed oppure associativo: + if (array_keys($data['attachments']) !== range(0, count($data['attachments']) - 1)) { + // è un array associativo, ovvero gli allegati sono raggruppati per tag: + $data['attachments'] = collection($data['attachments']) + ->map(function ($tagged_attachments, $tag) use ($data, $filename_as_tag) { + return collection($tagged_attachments)->map(function ($tagged_attachment_obj, $index) use ($tag, $data, $filename_as_tag) { + $tagged_attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($tagged_attachment_obj); + $tagged_attachment['tag'] = $tag; + if ($filename_as_tag) { + $exploded_name = explode(".", $tagged_attachment['name']); + $extension = $exploded_name[count($exploded_name) - 1]; + $tagged_attachment['name'] = $data['authority_identification_code_civil_engineering_office'] . "_$tag.$extension"; + } + if (isset($data['geo-attachments'][$tag][$index])) $tagged_attachment['geo'] = $data['geo-attachments'][$tag][$index]; + return $tagged_attachment; + })->toArray(); + }) + ->reduce(function ($acc, $attachments) { + return array_merge($acc, $attachments); + }, []); + } else { + $data['attachments'] = collection($data['attachments']) + ->map(function ($attachment_obj, $index) use ($data) { + $attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($attachment_obj); + if (isset($data['geo-attachments'][$index])) $attachment['geo'] = $data['geo-attachments'][$index]; + return $attachment; + }) + ->toArray(); + } + $data['attachments'] = array_values(collection($data['attachments'])->filter(function ($attachment, $key) { + return isset($attachment['error']) && $attachment['error'] == 0; + })->toArray()); + if (count($data['attachments']) == 0) { + unset($data['attachments']); + } + } else { + unset($data['attachments']); + } + } + if (isset($data['geo-attachments'])) unset($data['geo-attachments']); + } + + public function beforeSave(EventInterface $event, Entity $entity, \ArrayObject $options) + { + if (!$this->getConfig('attachment') || !is_array($this->getConfig('attachment')) || $this->getConfig('attachment.required') === null || !is_bool($this->getConfig('attachment.required')) || $this->getConfig('attachment.one_public') === null || !is_bool($this->getConfig('attachment.one_public')) || $this->getConfig('attachment.protected') === null || !is_bool($this->getConfig('attachment.protected'))) { + $entity->setErrors(['id' => ['You must pass a valid "attachment" option. Either remove "Attachments" behaviour from the table "' . $entity->getSource() . '" or pass a valid "attachment" option wich must contain the keys: "required", "one_public" and "protected"!']]); + return false; + } + if ($this->getConfig('attachment.accept_only') && is_array($this->getConfig('attachment.accept_only'))) { + $valid_attachment_extensions = $this->getConfig('attachment.accept_only'); + + if (isset($entity->attachments) && is_array($entity->attachments)) { + foreach ($entity->attachments as $attachment) { + $file_name_parts = explode(".", $attachment['name']); + if (count($file_name_parts) < 2) { + $entity->setError('attachment', __('Allegato "{0}" non valido! Estensione file NON presente!', $attachment['name'])); + return false; + } + $file_name_extension = count($file_name_parts) > 1 ? strtolower($file_name_parts[count($file_name_parts) - 1]) : ''; + if (!in_array('.' . $file_name_extension, $valid_attachment_extensions)) { + $entity->setError('attachment', __('Allegato "{0}" non valido! Estensione file "{1}" non ammessa!', $attachment['name'], $file_name_extension)); + return false; + } + } + } + } + + if (!TableRegistry::getTableLocator()->get($entity->getSource())->newEmptyEntity()->isAccessible('attachments')) { + $entity->setErrors(['id' => ['"attachments" key in $_accessible array of class "' . get_class($entity) . '" is missing. Either remove "Attachments" behaviour from the table "' . $entity->getSource() . '" or add "attachments" in $_accessible array!']]); + return false; + } + if (!TableRegistry::getTableLocator()->get($entity->getSource())->newEmptyEntity()->isAccessible('removefiles')) { + $entity->setErrors(['id' => ['"removefiles" key in $_accessible array of class "' . get_class($entity) . '" is missing. Either remove "Attachments" behaviour from the table "' . $entity->getSource() . '" or add "removefiles" in $_accessible array!']]); + return false; + } + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_id') === null && !$this->_table->behaviors()->has('ControllableObjectInterface')) { + $entity->setErrors(['id' => ['Both "controllable_object_id" field and "ControllableObjectInterface" behavior are missing. Either add the field or the behaviour to the table "' . $entity->getSource() . '"']]); + return false; + } + if ($this->_table->behaviors()->has('ControllableObjectInterface') && isset($options['associated'])) { + $options['associated'][] = 'ControllableObjectInterfaces'; + } + } + + public function afterSave(EventInterface $event, Entity $entity, \ArrayObject $options) + { + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_id') !== null) { + $co = TableRegistry::getTableLocator()->get('ControllableObjects')->find()->where(['ControllableObjects.id' => $entity->controllable_object_id])->first(); + if (!$co) { + throw new \Exception('Error retrieving controllable_object!'); + } + } else { + $coi = TableRegistry::getTableLocator()->get('ControllableObjectInterfaces')->find()->contain(['ControllableObjects'])->where(['ControllableObjectInterfaces.id' => $entity->controllable_object_interface_id])->first(); + if (!$coi || !isset($coi->controllable_object)) { + throw new \Exception('Error retrieving controllable_object from interface!'); + } + $co = $coi->controllable_object; + } + // numero di allegati attualmente associati: + $saved_attachment_file_names = $co->attachment_file_names; + $attachments_saved = is_array($saved_attachment_file_names) ? count($saved_attachment_file_names) : 0; + + if (isset($entity->removefiles) && is_array($entity->removefiles)) { + foreach($entity->removefiles as $removefile) { + if (!$co->deleteAttachment((Int)$removefile['id'])) { + throw new \Exception('Error during attachment delete!'); + } + $attachments_saved--; + } + } + + if (isset($entity->attachments) && is_array($entity->attachments)) { + foreach ($entity->attachments as $attachment) { + if (!isset($attachment['name']) || !isset($attachment['type']) || !isset($attachment['tmp_name']) || !isset($attachment['error']) || !isset($attachment['size'])) { + throw new \Exception('Invalid Attachments! Please make sure submitted form is encoded properly (type = file)'); + } + if ($attachment['error'] !== 0) { + continue; + } + $tags = isset($attachment['tag']) ? [$attachment['tag']] : []; + $geo = isset($attachment['geo']) ? $attachment['geo'] : []; + + // signature for method addAttachment(?String $filename = null, ?Int $fileSize = null, ?String $tmpPath = null, ?String $mime = null, ?int $private = 0, ?Bool $onePublic = false, ?Bool $protected = false, Array $tags = [], Array $geo = [], $skip_form_check = false) + if (!$co->addAttachment($attachment['name'], $attachment['size'], $attachment['tmp_name'], $attachment['type'], 0, $this->getConfig('attachment.one_public'), $this->getConfig('attachment.protected'), $tags, $geo)) { + throw new \Exception('Error saving attachment!'); + } + $attachments_saved++; + } + } + + if ((!isset($options['skip_attachment_check']) || !$options['skip_attachment_check']) && $this->getConfig('attachment.required') && $attachments_saved == 0) { + throw new \Exception(__('L\'allegato è obbligatorio!')); + } + } +} + +?> diff --git a/idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php b/idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php new file mode 100644 index 0000000..da00859 --- /dev/null +++ b/idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php @@ -0,0 +1,42 @@ +_table->belongsTo('ControllableObjectInterfaces'); + } + + public function beforeSave(EventInterface $event, Entity $entity, \ArrayObject $options) + { + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_id') !== null) { + $entity->setErrors(['id' => ['"controllable_object_id" field found. Either remove "ControllableObjectInterface" behaviour or remove that field from the table "' . $entity->source() . '"']]); + return false; + } + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_interface_id') === null) { + $entity->setErrors(['id' => ['"controllable_object_interface_id" field is missing. Either remove "ControllableObjectInterface" behaviour or add the missing field to the table "' . $entity->source() . '"']]); + return false; + } + if (!isset($entity->controllable_object_interface_id)) { + // recuperiamo l'id del relativo controllable_object_interface + $coit = TableRegistry::getTableLocator()->get('ControllableObjectInterfaceTypes')->find()->where(['ControllableObjectInterfaceTypes.table' => $entity->getSource()])->first(); + if (!$coit) { + $entity->setErrors(['controllable_object_interface_id' => ['"controllable_object_interface_type" not found. Either remove "ControllableObjectInterface" behaviour from the table "' . $entity->getSource() . '" or add related entry in "controllable_object_interface_types" table!']]); + return false; + } + // la seguente istruzione serve per triggerare il before marshal di controllable_object_interface che si occuperà di tutto il resto + $entity->controllable_object_interface = $this->_table->ControllableObjectInterfaces->newEntity(['controllable_object_interface_type_id' => $coit->id]); + } + } +} + +?> diff --git a/idrocap_wa/src/Model/Entity/Actor.php b/idrocap_wa/src/Model/Entity/Actor.php new file mode 100644 index 0000000..85bb828 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Actor.php @@ -0,0 +1,302 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'actor_type_id' => true, + 'deleted' => true, + 'actor_type' => true, + 'deliveries' => true, + 'dispatching_task_items' => true, + 'groups' => true, + 'organisations' => true, + 'users' => true, + ]; + + protected array $_virtual = [ + 'contacts', + ]; + + /** + * _getContacts + * + * @return String + */ + protected function _getContacts(): String + { + // se la entity è stata appena creata o è di tipo diverso da "organisation" o "user": + if ($this->isNew() || !in_array($this->actor_type_id, [1,5])) return ""; + + // se non vi è un utente loggato: + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return ""; + + // costruiamo la capability prefix a seconda che l'actor è un organisation o user: + $capability_prefix = $this->actor_type_id == 1 ? "configuration.organisations.view_" : "configuration.users.view_"; + + // recuperiamo l'id della organisation (o della organisation di appartenenza, qualora l'actor fosse uno user): + $organisation_id = $this->actor_type_id == 1 ? TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.actor_id' => $this->id])->first()->id ?? null : TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.actor_id' => $this->id])->first()->organisation_id ?? null; + + $contacts = TableRegistry::getTableLocator()->get('Deliveries')->find() + ->contain(['MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]) + ->where(['Deliveries.actor_id' => $this->id]) + ->order(['Deliveries.delivery_type_id' => 'ASC']) + ->all() + ->reduce(function ($acc, $contact) use ($user, $capability_prefix, $organisation_id) { + switch ($contact->delivery_type_id) { + case 1: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $mobile_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : "**************"; + } else { + // se l'actor è uno user: + $mobile_phone_value = $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'mobile_phone_foo') && $user->organisation_id == $organisation_id ? $contact->mobile_phone->value : "**************"); + } + $contact_value = __('Cellulare ({0}): {1}', $contact->mobile_phone->mobile_phone_description->description, $mobile_phone_value); + break; + case 2: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_fax_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : "**************"; + } else { + // se l'actor è uno user: + $contact_fax_value = $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'fax_foo') && $user->organisation_id == $organisation_id ? $contact->fax->value : "**************"); + } + $contact_value = __('Fax ({0}): {1}', $contact->fax->fax_description->description, $contact_fax_value); + break; + case 3: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_email_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : "**************"; + } else { + // se l'actor è uno user: + $contact_email_value = $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'email_foo') && $user->organisation_id == $organisation_id ? $contact->email->value : "**************"); + } + $contact_value = __('Email ({0}): {1}', $contact->email->email_description->description, $contact_email_value); + break; + case 4: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : "**************"; + } else { + // se l'actor è uno user: + $contact_phone_value = $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'phone_foo') && $user->organisation_id == $organisation_id ? $contact->phone->value : "**************"); + } + $contact_value = __('Telefono ({0}): {1}', $contact->phone->phone_description->description, $contact_phone_value); + break; + case 5: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_telegram_chat_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : "**************"; + } else { + // se l'actor è uno user: + $contact_telegram_chat_value = $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'telegram_chat_foo') && $user->organisation_id == $organisation_id ? $contact->telegram_chat->value : "**************"); + } + $contact_value = __('Telegram Chat ID: {0}', $contact_telegram_chat_value); + break; + case 6: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_pec_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : "**************"; + } else { + // se l'actor è uno user: + $contact_pec_value = $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'pec_foo') && $user->organisation_id == $organisation_id ? $contact->pec->value : "**************"); + } + $contact_value = __('PEC ({0}): {1}', $contact->pec->pec_description->description, $contact_pec_value); + break; + default: + $contact_value = ""; + break; + } + if ($contact_value != "") $acc[] = $contact_value; + return $acc; + }, []); + + return implode(", ", $contacts); + } + + /** + * getContactsList + * + * @return Array + */ + public function getContactsList(): Array + { + $contacts = []; + + // se la entity è stata appena creata o è di tipo diverso da "organisation" o "user": + if ($this->isNew() || !in_array($this->actor_type_id, [1,5])) return $contacts; + + // se non vi è un utente loggato: + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return $contacts; + + // costruiamo la capability prefix a seconda che l'actor è un organisation o user: + $capability_prefix = $this->actor_type_id == 1 ? "configuration.organisations.view_" : "configuration.users.view_"; + + // recuperiamo l'id della organisation (o della organisation di appartenenza, qualora l'actor fosse uno user): + $organisation_id = $this->actor_type_id == 1 ? TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.actor_id' => $this->id])->first()->id ?? null : TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.actor_id' => $this->id])->first()->organisation_id ?? null; + + $contacts = TableRegistry::getTableLocator()->get('Deliveries')->find() + ->contain(['MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]) + ->where(['Deliveries.actor_id' => $this->id]) + ->order(['Deliveries.delivery_type_id' => 'ASC']) + ->all() + ->reduce(function ($acc, $contact) use ($user, $capability_prefix, $organisation_id) { + $delivery_type_description = null; + $contact_description = null; + $contact_value = null; + + switch ($contact->delivery_type_id) { + case 1: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $mobile_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : "**************"; + } else { + // se l'actor è uno user: + $mobile_phone_value = $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'mobile_phone_foo') && $user->organisation_id == $organisation_id ? $contact->mobile_phone->value : "**************"); + } + $delivery_type_description = 'mobiles'; + $contact_description = $contact->mobile_phone->mobile_phone_description->description; + $contact_value = $mobile_phone_value; + break; + case 2: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_fax_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : "**************"; + } else { + // se l'actor è uno user: + $contact_fax_value = $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'fax_foo') && $user->organisation_id == $organisation_id ? $contact->fax->value : "**************"); + } + $delivery_type_description = 'faxes'; + $contact_description = $contact->fax->fax_description->description; + $contact_value = $contact_fax_value; + break; + case 3: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_email_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : "**************"; + } else { + // se l'actor è uno user: + $contact_email_value = $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'email_foo') && $user->organisation_id == $organisation_id ? $contact->email->value : "**************"); + } + $delivery_type_description = 'emails'; + $contact_description = $contact->email->email_description->description; + $contact_value = $contact_email_value; + break; + case 4: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : "**************"; + } else { + // se l'actor è uno user: + $contact_phone_value = $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'phone_foo') && $user->organisation_id == $organisation_id ? $contact->phone->value : "**************"); + } + $delivery_type_description = 'phones'; + $contact_description = $contact->phone->phone_description->description; + $contact_value = $contact_phone_value; + break; + case 5: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_telegram_chat_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : "**************"; + } else { + // se l'actor è uno user: + $contact_telegram_chat_value = $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'telegram_chat_foo') && $user->organisation_id == $organisation_id ? $contact->telegram_chat->value : "**************"); + } + $delivery_type_description = 'telegram_chats'; + $contact_description = ''; + $contact_value = $contact_telegram_chat_value; + break; + case 6: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_pec_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : "**************"; + } else { + // se l'actor è uno user: + $contact_pec_value = $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'pec_foo') && $user->organisation_id == $organisation_id ? $contact->pec->value : "**************"); + } + $delivery_type_description = 'pecs'; + $contact_description = $contact->pec->pec_description->description; + $contact_value = $contact_pec_value; + break; + default: + break; + } + if (isset($delivery_type_description) && isset($contact_description) && isset($contact_value)) { + $acc[$delivery_type_description][] = ['description' => $contact_description, 'value' => $contact_value]; + } + return $acc; + }, []); + + return $contacts; + } + + /** + * hasContactsWithNotificationsOfType + * + * @param String $contact_type + * @return Bool + */ + public function hasContactsWithNotificationsOfType(String $contact_type): Bool + { + if (!in_array($contact_type, ['PushNotifications', 'MobilePhones', 'Faxes', 'Emails', 'TelegramChats', 'Pecs'])) return false; + if (!isset($this->_fields['id'])) return false; + + return TableRegistry::getTableLocator()->get($contact_type)->find() + ->matching('Deliveries') + ->where(['enable_notifications' => true, 'Deliveries.actor_id' => $this->_fields['id']]) + ->limit(1) + ->first() !== null; + } + + /** + * getContactsWithNotificationsOfType + * + * @param String $contact_type + * @return Array + */ + public function getContactsWithNotificationsOfType(String $contact_type): Array + { + if (!in_array($contact_type, ['PushNotifications', 'MobilePhones', 'Faxes', 'Emails', 'TelegramChats', 'Pecs'])) return []; + if (!isset($this->_fields['id'])) return []; + + return TableRegistry::getTableLocator()->get($contact_type)->find() + ->matching('Deliveries') + ->where(['enable_notifications' => true, 'Deliveries.actor_id' => $this->_fields['id']]) + ->all() + ->toArray(); + } +} diff --git a/idrocap_wa/src/Model/Entity/ActorType.php b/idrocap_wa/src/Model/Entity/ActorType.php new file mode 100644 index 0000000..59b2602 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ActorType.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'entity' => true, + 'table' => true, + 'description' => true, + 'actors' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Applicant.php b/idrocap_wa/src/Model/Entity/Applicant.php new file mode 100644 index 0000000..a80cd17 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Applicant.php @@ -0,0 +1,81 @@ + + */ + protected array $_accessible = [ + 'name' => true, + 'surname' => true, + 'company_name' => true, + 'tax_code' => true, + 'vat_number' => true, + 'address' => true, + 'district' => true, + 'province' => true, + 'pec_address' => true, + 'email_address' => true, + 'water_drawing_paperworks' => true, + ]; + + protected array $_virtual = [ + 'applicant_full_description', + ]; + + /** + * _getApplicantFullDescription + * + * Virtual Field that returns the applicant full description + * + * @return string + */ + protected function _getApplicantFullDescription(): string + { + $tax_code = $this->_fields['tax_code']; + if (empty($this->_fields['vat_number'])) { + $surname = $this->_fields['surname']; + $name = $this->_fields['name']; + return "$surname $name CF $tax_code"; + } else { + $company_name = $this->_fields['company_name']; + $address = $this->_fields['address']; + $district = $this->_fields['district']; + $province = $this->_fields['province']; + $vat_number = $this->_fields['vat_number']; + return "$company_name $address $district ($province) CF $tax_code P.IVA $vat_number"; + } + } + + protected function _setTaxCode($value) + { + return strtoupper($value); + } +} diff --git a/idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php b/idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php new file mode 100644 index 0000000..c0116c9 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php @@ -0,0 +1,37 @@ + + */ + protected array $_accessible = [ + 'applicant_id' => true, + 'water_drawing_paperwork_id' => true, + 'is_primary_applicant' => true, + 'applicant' => true, + 'water_drawing_paperwork' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Attachment.php b/idrocap_wa/src/Model/Entity/Attachment.php new file mode 100644 index 0000000..d04b458 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Attachment.php @@ -0,0 +1,86 @@ + + */ + protected array $_accessible = [ + 'original_file_name' => true, + 'original_file_size' => true, + 'file_name' => true, + 'mimetype' => true, + 'upload_date' => true, + 'controllable_object_id' => true, + 'container_controllable_object_id' => true, + 'relevant' => true, + 'private' => true, + 'controllable_object' => true, + 'container_controllable_object' => true, + 'tags' => true, + ]; + + /** + * _getRelativeUrl + * + * @return ?String + */ + protected function _getRelativeUrl() + { + if(isset($this->_fields['file_name'])) + { + return Configure::read('App.attachmentsUrl')."/".$this->_fields['file_name']; + } + + return null; + } + + /** + * _getHumanOriginalFileSize + * + * @return ?String + */ + protected function _getHumanOriginalFileSize() + { + if(!isset($this->_fields['original_file_size'])) + { + return null; + } + $bytes = (String)$this->_fields['original_file_size']; + $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); + $factor = floor((strlen($bytes) - 1) / 3); + return sprintf("%.2f", $bytes / pow(1024, $factor)) . " " . @$size[$factor]; + } +} diff --git a/idrocap_wa/src/Model/Entity/BackgroundTask.php b/idrocap_wa/src/Model/Entity/BackgroundTask.php new file mode 100644 index 0000000..7b6cf21 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/BackgroundTask.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'command' => true, + 'data' => true, + 'dgroup' => true, + 'status' => true, + 'was_synced' => true, + 'created' => true, + 'modified' => true, + 'dispatching_tasks' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CadastralCropType.php b/idrocap_wa/src/Model/Entity/CadastralCropType.php new file mode 100644 index 0000000..e7ef6f4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CadastralCropType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_intended_uses' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php b/idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php new file mode 100644 index 0000000..78f6a7b --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'capability_id' => true, + 'menu_item_id' => true, + 'capability' => true, + 'menu_item' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php b/idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php new file mode 100644 index 0000000..c950e4d --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'capability_id' => true, + 'menu_section_id' => true, + 'capability' => true, + 'menu_section' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Capability.php b/idrocap_wa/src/Model/Entity/Capability.php new file mode 100644 index 0000000..b21d3ad --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Capability.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'value' => true, + 'priority' => true, + 'capability_group_id' => true, + 'priority_group_id' => true, + 'longdescription' => true, + 'deleted' => true, + 'is_configurable' => true, + 'capability_group' => true, + 'priority_group' => true, + 'permissions' => true, + 'menu_items' => true, + 'menu_sections' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CapabilityGroup.php b/idrocap_wa/src/Model/Entity/CapabilityGroup.php new file mode 100644 index 0000000..a974025 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CapabilityGroup.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'is_configurable' => true, + 'capabilities' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObject.php b/idrocap_wa/src/Model/Entity/ControllableObject.php new file mode 100644 index 0000000..45b973c --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObject.php @@ -0,0 +1,297 @@ + + */ + protected array $_accessible = [ + 'created' => true, + 'modified' => true, + 'organisation_id' => true, + 'controllable_object_type_id' => true, + 'create_user_id' => true, + 'edit_user_id' => true, + 'edit_organisation_id' => true, + 'deleted' => true, + 'organisation' => true, + 'controllable_object_type' => true, + 'user' => true, + 'attachments' => true, + 'controllable_object_interfaces' => true, + 'location' => true, + ]; + + /** + * getHashedFileName + * + * @param ?String $original_file_name + * @param ?Bool $sha512 + * @return ?String + */ + private function getHashedFileName(?String $original_file_name = null, ?Bool $sha512 = false): ?String { + if ($original_file_name == null) { + return null; + } + $rowData = $original_file_name . microtime(true); + return $sha512 ? hash('sha512', $rowData) : md5($rowData); + } + + /** + * getDuplicatedFilename + * + * @param String $filename + * @param ?Int $container_co_id + * @return String + */ + private function getDuplicatedFilename(String $filename, ?Int $container_co_id = null): String { + + $co_id = isset($container_co_id) ? $container_co_id : $this->_fields['id']; + $attachmentsTable = TableRegistry::getTableLocator()->get('Attachments'); + $file_exists = $attachmentsTable->find()->where(['Attachments.original_file_name' => $filename, 'Attachments.container_controllable_object_id' => $co_id])->first(); + if (!$file_exists) { + return $filename; + } + + $lastDotIndex = strrpos($filename, "."); + if ($lastDotIndex) { + $filename_without_extension = substr($filename, 0, $lastDotIndex); + $filename_extension = substr($filename, $lastDotIndex); + if ($filename_extension == ".") { + $filename_without_extension = $filename; + $filename_extension = ""; + } + } else { + $filename_without_extension = $filename; + $filename_extension = ""; + } + + $whereCondition = "original_file_name REGEXP '^" . $filename_without_extension . "_[[:digit:]]*" . $filename_extension . "$'"; + + $numbers = $attachmentsTable->find() + ->where([$whereCondition]) + ->where(['Attachments.container_controllable_object_id' => $co_id]) + ->all() + ->map(function($value, $key) { + $filename_exploded_array = explode("_", $value->original_file_name); + $number_with_ext_array = explode(".", $filename_exploded_array[count($filename_exploded_array) - 1]); + $number = $number_with_ext_array[0]; + return $number; + }) + ->toArray(); + + $count = count($numbers); + for ($index = 0; $index < count($numbers); $index++) { + if (!in_array(($index + 2), $numbers)) { + $count = $index; + break; + } + } + + return $filename_without_extension . "_" . ($count + 2) . $filename_extension; + } + + /** + * _getAttachmentFileNames + * + * @return Array + */ + protected function _getAttachmentFileNames() { + if($this->isNew()) + { + return []; + } + $attachmentFileNames = TableRegistry::getTableLocator()->get('Attachments')->find() + ->matching('ControllableObjects') + ->where(['Attachments.container_controllable_object_id' => $this->_fields['id']]) + ->all() + ->reduce(function ($acc ,$value) { + $acc[$value->file_name] = $value->original_file_name; + return $acc; + }, []); + return $attachmentFileNames; + } + + /** + * deleteAttachment + * + * @param Int $co_id + * @return Bool + */ + public function deleteAttachment(Int $co_id): Bool { + $controllableObjectsTable = TableRegistry::getTableLocator()->get('ControllableObjects'); + + if ($co_id == null) { + return false; + } + $attachmentCo = $controllableObjectsTable + ->find() + ->where(['ControllableObjects.id' => $co_id]) + ->first(); + if (!$attachmentCo) { + return false; + } + if (!$controllableObjectsTable->delete($attachmentCo)) { + return false; + } + return true; + } + + /** + * addAttachment + * + * @param ?String $filename + * @param ?Int $fileSize + * @param ?String $tmpPath + * @param ?String $mime + * @param ?int $private + * @param ?Bool $onePublic + * @param ?Bool $protected + * @param Array $tags + * @param Array $geo + * @throws \Exception + * @return Bool + */ + public function addAttachment(?String $filename = null, ?Int $fileSize = null, ?String $tmpPath = null, ?String $mime = null, ?int $private = 0, ?Bool $onePublic = false, ?Bool $protected = false, Array $tags = [], Array $geo = [], $skip_form_check = false): Bool + { + $co_id = $this->_fields['id']; + $attachmentsTable = TableRegistry::getTableLocator()->get('Attachments'); + + if ($filename == null) { + return false; + } + if ($fileSize == null) { + return false; + } + if ($tmpPath == null) { + return false; + } + if ($mime == null) { + return false; + } + + // 1 - check if attachment has been uploaded through input form or has been tampered with; + // 2 - check if attachment real type is allowed: + AttachmentChecker::check(['tmp_name' => $tmpPath, 'name' => $filename, 'type' => $mime, 'size' => $fileSize], $skip_form_check); + + if ($private == 0 && $onePublic) { + $existing_files = $attachmentsTable->find()->where(['Attachments.container_controllable_object_id' => $co_id, 'Attachments.private' => 0]); + foreach ($existing_files as $existing_file) { + if (!$this->deleteAttachment($existing_file->controllable_object_id)) { + return false; + } + } + } + + $file_name = $this->getHashedFileName($filename); + + $attachment_data = [ + 'container_controllable_object_id' => $co_id, + 'original_file_name' => $this->getDuplicatedFilename($filename, $co_id), + 'original_file_size' => $fileSize, + 'file_name' => $file_name, + 'url_access' => $protected ? $this->getHashedFileName($filename, true) : null, + 'mimetype' => $mime, + 'upload_date' => DateTime::now(), + 'private' => $private, + 'controllable_object' => [ + 'controllable_object_type_id' => 8, + ], + ]; + + if (!empty($geo['longitude']) && !empty($geo['latitude'])) { + $attachment_data['controllable_object']['location'] = [ + 'description' => $geo['longitude'] . ' ' . $geo['latitude'], + 'coordinates' => $geo['longitude'] . ' ' . $geo['latitude'], + 'geotype' => 'marker', + 'geom' => '{"type":"Point","coordinates":[' . $geo['longitude'] . ',' . $geo['latitude'] . ']}', + ]; + + if (!GeoValidation::isValidGeometry(json_decode($attachment_data['controllable_object']['location']['geom']))) { + throw new \Exception(__('Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + } + + $associated = [ + 'ControllableObjects' => [ + 'associated' => ['Locations'] + ], + ]; + + $attachment = $attachmentsTable->newEntity($attachment_data, ['associated' => $associated]); + + try + { + $res = \App\WGS\FileStorage\FileStorageFactory::create()->saveFile(Configure::read('App.attachmentsPath')."/".$co_id."/".$file_name,$tmpPath); + if (is_array($tags) && !empty($tags)) { + $tagsTable = TableRegistry::getTableLocator()->get('Tags'); + $tags = $tagsTable->find()->where(['Tags.code IN' => $tags])->toArray(); + $attachment->tags = $tags; + } + + if (!$attachmentsTable->save($attachment)) { + return false; + } + + return true; + } + catch(\Exception $we) + { + return false; + } + + return true; + } + + /** + * getSpecialisationEntity + * + * @return Cake\ORM\Entity|null + */ + public function getSpecialisationEntity() + { + $co_type = TableRegistry::getTableLocator()->get('ControllableObjectTypes')->find()->where(['ControllableObjectTypes.id' => $this->_fields['controllable_object_type_id']])->first(); + if (!$co_type) return null; + $table = \Cake\Utility\Inflector::camelize($co_type->controller); + $specialisation_entity = TableRegistry::getTableLocator()->get($table)->find()->where(["$table.controllable_object_id" => $this->_fields['id']])->first(); + if (!$specialisation_entity) return null; + return $specialisation_entity; + } +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObjectInterface.php b/idrocap_wa/src/Model/Entity/ControllableObjectInterface.php new file mode 100644 index 0000000..1cb0462 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObjectInterface.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'controllable_object_id' => true, + 'controllable_object_interface_type_id' => true, + 'controllable_object' => true, + 'controllable_object_interface_type' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php b/idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php new file mode 100644 index 0000000..32bde37 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php @@ -0,0 +1,34 @@ + + */ + protected array $_accessible = [ + 'entity' => true, + 'table' => true, + 'description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObjectType.php b/idrocap_wa/src/Model/Entity/ControllableObjectType.php new file mode 100644 index 0000000..1ae34a4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObjectType.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'controller' => true, + 'label' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/County.php b/idrocap_wa/src/Model/Entity/County.php new file mode 100644 index 0000000..a3f0df1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/County.php @@ -0,0 +1,52 @@ + + */ + protected array $_accessible = [ + 'SHAPE' => true, + 'cod_rip' => true, + 'cod_reg' => true, + 'cod_prov' => true, + 'cod_cm' => true, + 'cod_uts' => true, + 'den_prov' => true, + 'den_cm' => true, + 'den_uts' => true, + 'sigla' => true, + 'tipo_uts' => true, + 'shape_leng' => true, + 'shape_area' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Delivery.php b/idrocap_wa/src/Model/Entity/Delivery.php new file mode 100644 index 0000000..4f4a688 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Delivery.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'actor_id' => true, + 'delivery_type_id' => true, + 'deleted' => true, + 'actor' => true, + 'delivery_type' => true, + 'emails' => true, + 'faxes' => true, + 'mobile_phones' => true, + 'phones' => true, + 'push_notifications' => true, + 'telegram_chats' => true, + 'telegram_contacts' => true, + 'pecs' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DeliveryType.php b/idrocap_wa/src/Model/Entity/DeliveryType.php new file mode 100644 index 0000000..44e6434 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DeliveryType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deliveries' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DispatchingTask.php b/idrocap_wa/src/Model/Entity/DispatchingTask.php new file mode 100644 index 0000000..0fd2fb1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DispatchingTask.php @@ -0,0 +1,47 @@ + + */ + protected array $_accessible = [ + 'dispatching_task_group' => true, + 'dispatching_task_status_id' => true, + 'created' => true, + 'modified' => true, + 'retries' => true, + 'failed' => true, + 'background_task_id' => true, + 'dispatching_task_status' => true, + 'background_task' => true, + 'dispatching_task_items' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DispatchingTaskItem.php b/idrocap_wa/src/Model/Entity/DispatchingTaskItem.php new file mode 100644 index 0000000..000b606 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DispatchingTaskItem.php @@ -0,0 +1,47 @@ + + */ + protected array $_accessible = [ + 'dispatching_task_id' => true, + 'actor_id' => true, + 'system_dispatched' => true, + 'actor_dispatching_bitmask' => true, + 'performed_dispatching_bitmask' => true, + 'not_performed_dispatching_bitmask' => true, + 'created' => true, + 'modified' => true, + 'dispatching_task' => true, + 'actor' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php b/idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php new file mode 100644 index 0000000..9625c26 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'dispatching_tasks' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/District.php b/idrocap_wa/src/Model/Entity/District.php new file mode 100644 index 0000000..bdcb1a2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/District.php @@ -0,0 +1,52 @@ + + */ + protected array $_accessible = [ + 'SHAPE' => true, + 'cod_rip' => true, + 'cod_reg' => true, + 'cod_prov' => true, + 'cod_cm' => true, + 'cod_uts' => true, + 'pro_com' => true, + 'pro_com_t' => true, + 'comune' => true, + 'comune_a' => true, + 'cc_uts' => true, + 'shape_leng' => true, + 'shape_area' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Email.php b/idrocap_wa/src/Model/Entity/Email.php new file mode 100644 index 0000000..17a52c8 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Email.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'is_system' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'email_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'email_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/EmailDescription.php b/idrocap_wa/src/Model/Entity/EmailDescription.php new file mode 100644 index 0000000..c1acab8 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/EmailDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'emails' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Fax.php b/idrocap_wa/src/Model/Entity/Fax.php new file mode 100644 index 0000000..0c2aa54 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Fax.php @@ -0,0 +1,41 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'fax_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'fax_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/FaxDescription.php b/idrocap_wa/src/Model/Entity/FaxDescription.php new file mode 100644 index 0000000..47b2a50 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/FaxDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'faxes' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Filter.php b/idrocap_wa/src/Model/Entity/Filter.php new file mode 100644 index 0000000..d40ed66 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Filter.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'category' => true, + 'description' => true, + 'filter_type' => true, + 'class_name' => true, + 'search' => true, + 'associations' => true, + 'order_number' => true, + 'sys_admin_only' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Group.php b/idrocap_wa/src/Model/Entity/Group.php new file mode 100644 index 0000000..22e5dc4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Group.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'is_default' => true, + 'super_group' => true, + 'actor_id' => true, + 'is_editable' => true, + 'group_code' => true, + 'modified' => true, + 'actor' => true, + 'memberships' => true, + 'permissions' => true, + 'tags' => true, + 'capabilities' => true, + 'child_groups' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/GroupsGroup.php b/idrocap_wa/src/Model/Entity/GroupsGroup.php new file mode 100644 index 0000000..0ad9183 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/GroupsGroup.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'container_group_id' => true, + 'group_id' => true, + 'group' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Language.php b/idrocap_wa/src/Model/Entity/Language.php new file mode 100644 index 0000000..c73d283 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Language.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'language_code' => true, + 'users' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Location.php b/idrocap_wa/src/Model/Entity/Location.php new file mode 100644 index 0000000..c45ae59 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Location.php @@ -0,0 +1,56 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'coordinates' => true, + 'feature_collection' => true, + 'geom' => true, + 'controllable_object_id' => true, + 'controllable_object' => true, + 'location_attributes' => true, + ]; + + /** + * _getGeom + * + * @param mixed $value + * @return mixed + */ + protected function _getGeom($value) + { + if (!is_string($value) || empty(json_decode($value))) { + return $value; + } + return new QueryExpression("ST_GeomFromGeoJson('$value')"); + } +} diff --git a/idrocap_wa/src/Model/Entity/LocationAttribute.php b/idrocap_wa/src/Model/Entity/LocationAttribute.php new file mode 100644 index 0000000..677ade1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/LocationAttribute.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'location_id' => true, + 'district_code' => true, + 'district_name' => true, + 'county_code' => true, + 'county_name' => true, + 'region' => true, + 'area' => true, + 'location' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Map.php b/idrocap_wa/src/Model/Entity/Map.php new file mode 100644 index 0000000..6c2d3a3 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Map.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'code' => true, + 'name' => true, + 'url_layer' => true, + 'clusterize' => true, + 'visible' => true, + 'style' => true, + 'created' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MenuItem.php b/idrocap_wa/src/Model/Entity/MenuItem.php new file mode 100644 index 0000000..8c6e620 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MenuItem.php @@ -0,0 +1,82 @@ + + */ + protected array $_accessible = [ + 'title' => true, + 'icon' => true, + 'link' => true, + 'menu_item_id' => true, + 'menu_section_id' => true, + 'menu_order' => true, + 'menu_items' => true, + 'menu_section' => true, + 'capabilities' => true, + ]; + + protected array $_virtual = [ + 'menu_items', + ]; + + /** + * _getMenuItems + * + * @return Array + */ + protected function _getMenuItems(): Array + { + $menu_items = []; + + // bisogna recuperare le capabilities utente (se esiste un utente loggato) + $user = Router::getRequest()->getAttribute('identity'); + if ($user) { + $MenuItems = TableRegistry::getTableLocator()->get('MenuItems'); + $menu_items_subquery = $MenuItems + ->find() + ->select(['MenuItems.id']) + ->innerJoinWith('Capabilities') + ->where(['MenuItems.menu_item_id is NOT NULL', 'MenuItems.menu_item_id' => $this->id]) + ->where(['Capabilities.id IN' => $user->getCapabilityIds(true)]) + ->distinct(['MenuItems.id']); + + $menu_items = $MenuItems + ->find() + ->where(['MenuItems.id IN' => $menu_items_subquery]) + ->order(['MenuItems.menu_order' => 'ASC']) + ->toArray(); + } + return $menu_items; + + } +} diff --git a/idrocap_wa/src/Model/Entity/MenuSection.php b/idrocap_wa/src/Model/Entity/MenuSection.php new file mode 100644 index 0000000..e34130e --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MenuSection.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'title' => true, + 'icon' => true, + 'menu_items' => true, + 'capabilities' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Message.php b/idrocap_wa/src/Model/Entity/Message.php new file mode 100644 index 0000000..e788874 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Message.php @@ -0,0 +1,61 @@ + + */ + protected array $_accessible = [ + 'controllable_object_id' => true, + 'message_type_id' => true, + 'content' => true, + 'user_id' => true, + 'message_status_id' => true, + 'mgroup' => true, + 'event_string' => true, + 'last_update' => true, + 'organisation_id' => true, + 'contact' => true, + 'not_delivered_reason' => true, + 'controllable_object' => true, + 'message_type' => true, + 'user' => true, + 'message_status' => true, + 'organisation' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MessageStatus.php b/idrocap_wa/src/Model/Entity/MessageStatus.php new file mode 100644 index 0000000..25525a2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MessageStatus.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'messages' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MessageType.php b/idrocap_wa/src/Model/Entity/MessageType.php new file mode 100644 index 0000000..2e3d49f --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MessageType.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'label' => true, + 'dispatching_bitmask_weight' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MobileComponent.php b/idrocap_wa/src/Model/Entity/MobileComponent.php new file mode 100644 index 0000000..9cc4db4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MobileComponent.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'menu_item' => true, + 'is_enabled' => true, + 'capabilities' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MobilePhone.php b/idrocap_wa/src/Model/Entity/MobilePhone.php new file mode 100644 index 0000000..7a37091 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MobilePhone.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'is_system' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'mobile_phone_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'mobile_phone_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MobilePhoneDescription.php b/idrocap_wa/src/Model/Entity/MobilePhoneDescription.php new file mode 100644 index 0000000..5621fbc --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MobilePhoneDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'mobile_phones' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Notification.php b/idrocap_wa/src/Model/Entity/Notification.php new file mode 100644 index 0000000..0ab8381 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Notification.php @@ -0,0 +1,51 @@ + + */ + protected array $_accessible = [ + 'user_id' => true, + 'read_by_user' => true, + 'notification_type_id' => true, + 'info' => true, + 'created' => true, + 'thread' => true, + 'ngroup' => true, + 'controllable_object_id' => true, + 'user' => true, + 'notification_type' => true, + 'controllable_object' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/NotificationType.php b/idrocap_wa/src/Model/Entity/NotificationType.php new file mode 100644 index 0000000..9a02d79 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/NotificationType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'notifications' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Organisation.php b/idrocap_wa/src/Model/Entity/Organisation.php new file mode 100644 index 0000000..65eeffa --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Organisation.php @@ -0,0 +1,259 @@ + + */ + protected array $_accessible = [ + 'acronym' => true, + 'geoposition' => true, + 'address' => true, + 'district' => true, + 'cap' => true, + 'province' => true, + 'organisation_type_id' => true, + 'actor_id' => true, + 'pec' => true, + 'coordinates' => true, + 'feature_collection' => true, + 'deleted' => true, + 'photo' => true, + 'controllable_object_interface_id' => true, + 'organisation_type' => true, + 'actor' => true, + 'controllable_object_interface' => true, + 'messages' => true, + 'users' => true, + 'attachments' => true, + 'removefiles' => true, + ]; + + protected array $_hidden = [ + 'geoposition', + ]; + + protected array $_virtual = [ + 'mobile_phones', + 'phones', + 'emails', + 'pecs', + ]; + + /** + * can_view + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_view(User $user, Array &$options): Bool + { + if ($user->hasCapability(['configuration.organisations.read'])) + { + return true; + } else { + $options['error']['capabilities'] = ['configuration.organisations.read']; + return false; + } + } + + /** + * _getGeoposition + * + * @param mixed $value + * @return mixed + */ + protected function _getGeoposition($value) + { + if (!is_string($value) || empty(json_decode($value))) { + return $value; + } + return new QueryExpression("ST_GeomFromGeoJson('$value')"); + } + + protected function _getMobilePhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('MobilePhones')->find()->contain(['Deliveries', 'MobilePhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->mobile_phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getPhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('Phones')->find()->contain(['Deliveries', 'PhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getEmails() + { + if ($this->isNew()) return []; + $emails = TableRegistry::getTableLocator()->get('Emails')->find()->contain(['Deliveries', 'EmailDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->email_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $emails; + } + + protected function _getPecs() + { + if ($this->isNew()) return []; + $pecs = TableRegistry::getTableLocator()->get('Pecs')->find()->contain(['Deliveries', 'PecDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->pec_description->description, + 'value' => $row->value + ]; + }); + }); + return $pecs; + } + + /** + * getActor + * + * @return ?Actor + */ + public function getActor(): ?Actor + { + if (!isset($this->_fields['actor_id'])) return null; + return TableRegistry::getTableLocator()->get('Actors')->get($this->_fields['actor_id']); + } + + /** + * hasMobilePhonesWithNotifications + * + * @return Bool + */ + public function hasMobilePhonesWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * hasEmailsWithNotifications + * + * @return Bool + */ + public function hasEmailsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Emails'); + } + + /** + * hasPecsWithNotifications + * + * @return Bool + */ + public function hasPecsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Pecs'); + } + + /** + * getMobilePhonesWithNotifications + * + * @return Array + */ + public function getMobilePhonesWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * getEmailsWithNotifications + * + * @return Array + */ + public function getEmailsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Emails'); + } + + /** + * getPecsWithNotifications + * + * @return Array + */ + public function getPecsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Pecs'); + } + + /** + * getDispatchingBitmask + * + * @return ?Int + */ + public function getDispatchingBitmask(): ?Int + { + if (!isset($this->_fields['id'])) return null; + + $bitmask = 0; + + if ($this->hasMobilePhonesWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(1)->dispatching_bitmask_weight; + if ($this->hasEmailsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(3)->dispatching_bitmask_weight; + if ($this->hasPecsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(5)->dispatching_bitmask_weight; + + return $bitmask; + } +} diff --git a/idrocap_wa/src/Model/Entity/OrganisationType.php b/idrocap_wa/src/Model/Entity/OrganisationType.php new file mode 100644 index 0000000..8f41457 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/OrganisationType.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'organisations' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Pec.php b/idrocap_wa/src/Model/Entity/Pec.php new file mode 100644 index 0000000..30f9225 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Pec.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'is_system' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'pec_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'pec_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PecDescription.php b/idrocap_wa/src/Model/Entity/PecDescription.php new file mode 100644 index 0000000..fa0d5a7 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PecDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'pecs' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Permission.php b/idrocap_wa/src/Model/Entity/Permission.php new file mode 100644 index 0000000..2c9c685 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Permission.php @@ -0,0 +1,34 @@ + + */ + protected array $_accessible = [ + 'deleted' => true, + 'capability' => true, + 'group' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Phone.php b/idrocap_wa/src/Model/Entity/Phone.php new file mode 100644 index 0000000..b79ec75 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Phone.php @@ -0,0 +1,39 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'delivery_id' => true, + 'phone_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'phone_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PhoneDescription.php b/idrocap_wa/src/Model/Entity/PhoneDescription.php new file mode 100644 index 0000000..5fa42a3 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PhoneDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'phones' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Privacy.php b/idrocap_wa/src/Model/Entity/Privacy.php new file mode 100644 index 0000000..c77b2b5 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Privacy.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'created' => true + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PrivacyUser.php b/idrocap_wa/src/Model/Entity/PrivacyUser.php new file mode 100644 index 0000000..b521b22 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PrivacyUser.php @@ -0,0 +1,37 @@ + + */ + protected array $_accessible = [ + 'privacy_id' => true, + 'user_id' => true, + 'created' => true, + 'privacy' => true, + 'user' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PushNotification.php b/idrocap_wa/src/Model/Entity/PushNotification.php new file mode 100644 index 0000000..fe65c4e --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PushNotification.php @@ -0,0 +1,37 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'deleted' => true, + 'delivery' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Snapshot.php b/idrocap_wa/src/Model/Entity/Snapshot.php new file mode 100644 index 0000000..0d4e102 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Snapshot.php @@ -0,0 +1,47 @@ + + */ + protected array $_accessible = [ + 'controllable_object_type_id' => true, + 'controllable_object_id' => true, + 'object_snapshot' => true, + 'date' => true, + 'user_id' => true, + 'controller_action' => true, + 'unpacked_with_version' => true, + 'user' => true, + 'controllable_object' => true, + 'controllable_object_type' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Tag.php b/idrocap_wa/src/Model/Entity/Tag.php new file mode 100644 index 0000000..0f6f595 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Tag.php @@ -0,0 +1,56 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'code' => true, + 'class' => true, + 'attachments' => true, + 'groups' => true, + 'id' => true, + 'controllable_object_id' => true, + 'attachments' => true, + 'removefiles' => true, + 'controllable_object' => true, + ]; + + protected array $_virtual = [ + 'link', + ]; + + protected function _getLink(): string{ + if (empty($this->controllable_object_id)) return ''; + $attachment = TableRegistry::getTableLocator()->get('Attachments')->find()->where(['Attachments.container_controllable_object_id' => $this->controllable_object_id])->first(); + if(!isset($attachment->file_name)) return ''; + $link = $attachment->file_name; + return $link; + } +} diff --git a/idrocap_wa/src/Model/Entity/TelegramChat.php b/idrocap_wa/src/Model/Entity/TelegramChat.php new file mode 100644 index 0000000..4aef789 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/TelegramChat.php @@ -0,0 +1,41 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'telegram_chat_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'telegram_chat_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/TelegramContact.php b/idrocap_wa/src/Model/Entity/TelegramContact.php new file mode 100644 index 0000000..87329e2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/TelegramContact.php @@ -0,0 +1,51 @@ + + */ + protected array $_accessible = [ + 'phone_number' => true, + 'telegram_user_id' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'created' => true, + 'modified' => true, + 'deleted' => true, + 'telegram_contact_status_id' => true, + 'error_message' => true, + 'delivery' => true, + 'telegram_contact_status' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php b/idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php new file mode 100644 index 0000000..5e3c96a --- /dev/null +++ b/idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php @@ -0,0 +1,55 @@ + + */ + protected array $_accessible = [ + 'snapshot_id' => true, + 'unpacking_version' => true, + 'who' => true, + 'when' => true, + 'what' => true, + 'creator' => true, + 'created' => true, + 'modifier' => true, + 'modified' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_paperwork_status' => true, + 'gc_user' => true, + 'drar_user' => true, + 'snapshot' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/User.php b/idrocap_wa/src/Model/Entity/User.php new file mode 100644 index 0000000..ebfccf1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/User.php @@ -0,0 +1,643 @@ + + */ + protected array $_accessible = [ + 'organisation_id' => true, + 'username' => true, + 'password' => true, + 'surname' => true, + 'name' => true, + 'address' => true, + 'city' => true, + 'cap' => true, + 'tax_code' => true, + 'photo' => true, + 'user_photo' => true, // don't remove!!!!!!!!! + 'birthplace' => true, + 'birthday' => true, + 'gender' => true, + 'language_id' => true, + 'password_recovery_token' => true, + 'password_recovery_counter' => true, + 'actor_id' => true, + 'deleted' => true, + 'organisation' => true, + 'language' => true, + 'actor' => true, + 'memberships' => true, + 'messages' => true, + 'notifications' => true, + 'groups' => true, + "email_verification_code" => true, + "is_verified" => true, + "is_citizen" => true + ]; + + + + + /** + * Fields that are excluded from JSON versions of the entity. + * + * @var array + */ + protected array $_hidden = [ + 'password', + 'position', + ]; + + protected array $_virtual = [ + 'profiles', + 'mobile_phones', + 'emails', + 'phones', + 'pecs', + 'organisation_province' + ]; + + /** + * Authentication\IdentityInterface method + */ + public function getIdentifier(): array|string|int|null + { + return $this->id; + } + + /** + * Authentication\IdentityInterface method + */ + public function getOriginalData(): ArrayAccess|array + { + return $this; + } + + /** + * _setPassword + * + * @param String $password + * @return String + */ + protected function _setPassword(String $password) + { + $hasher = new DefaultPasswordHasher(); + return $hasher->hash($password); + } + + /** + * getCapabilityIds + * + * @param Bool $return_query_object + * @return Array|Query + */ + public function getCapabilityIds(Bool $return_query_object = false): Array|Query + { + $CapabilitiesTable = TableRegistry::getTableLocator()->get('Capabilities'); + + $capabilities = $CapabilitiesTable->find() + ->select(['id']); + + if (!isset($this->sys_admin) || !$this->sys_admin) { + $capabilities = $capabilities + ->matching('Groups.Users') + ->where(['Permissions.deleted IS NULL']) + ->where(['Users.id' => $this->id]) + ->distinct(); + } + + if (!$return_query_object) { + $capabilities = $capabilities + ->all() + ->extract('id') + ->toArray(); + } + + return $capabilities; + } + + /** + * hasCapability + * + * @param String|Array $capability + * @return Bool + */ + public function hasCapability(String|Array $capability): Bool + { + if (isset($this->sys_admin) && $this->sys_admin) return true; + + if (is_string($capability)) $capability = [$capability]; + return TableRegistry::getTableLocator()->get('Capabilities') + ->find() + ->where(['Capabilities.value IN' => $capability, 'Capabilities.id IN' => $this->getCapabilityIds(true)]) + ->first() !== null; + } + + + /** + * Verifica se l'utente ha solo la capability con priorità più bassa tra quelle fornite + * + * @param String|Array $capabilities + * @return Bool + */ + public function hasOnlyLowerPriorityCapability(String|Array $capabilities): Bool + { + if (isset($this->sys_admin) && $this->sys_admin) return false; + + $userCapabilities = TableRegistry::getTableLocator()->get('Capabilities') + ->find() + ->select(['value', 'priority']) + ->where(['Capabilities.value IN' => $capabilities, 'Capabilities.id IN' => $this->getCapabilityIds(true)]) + ->all() + ->toArray(); + + // Se l'utente non ha nessuna delle capability richieste, restituisco false + if (empty($userCapabilities)) return false; + + // A questo punto verifico se l'utente ha solo la capability con priorità più bassa + $hasPriority1 = false; + $hasPriority2 = false; + + foreach ($userCapabilities as $capability) { + if ($capability->priority == 1) { + $hasPriority1 = true; + } else if ($capability->priority == 2) { + $hasPriority2 = true; + } + } + return !$hasPriority1 && $hasPriority2; + } + + /** + * canActOnContactsForActor + * + * @param String $action + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + private function canActOnContactsForActor(String $action, Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + $contact_types = is_string($contact_types) ? [$contact_types] : $contact_types; + // se actor è di tipo "organizzazione": + if ($actor->actor_type_id == 1) { + // verifichiamo che l'utente abbia titolo a visualizzare i recapiti dell'organizzazione selezionata. + // o è la sua stessa organizzazione oppure necessita di almeno 1 delle seguenti capabilities: + $required_capabilities = collection($contact_types) + ->map(function ($contact_type) use ($action) { + return 'configuration.organisations.' . $action . '_' . $contact_type; + }) + ->toArray(); + if ($actor->organisation->id != $this->organisation_id && !$this->hasCapability($required_capabilities)) return false; + return true; + } + + // se actor è di tipo "utente": + if ($actor->actor_type_id == 5) { + // verifichiamo che l'utente abbia titolo a visualizzare i recapiti dell'utente selezionato. + // o l'utente selezionato è lo stesso utente, + // o l'utente selezionato appartiene alla stessa organizzazione dell'utente e possiede almeno una + // tra l'array_merge dei 2 seguenti array $required_capabilities e $required_foo_capabilities, + // oppure deve possedere almeno 1 delle capabilities di $required_capabilities soltanto: + $required_capabilities = collection($contact_types) + ->map(function ($contact_type) use ($action) { + return 'configuration.users.' . $action . '_' . $contact_type; + }) + ->toArray(); + $required_foo_capabilities = collection($contact_types) + ->map(function ($contact_type) use ($action) { + return 'configuration.users.' . $action . '_' . $contact_type . '_foo'; + }) + ->toArray(); + // se i recapiti sono relativi ad un'utente della stessa organizzazione dell'utente loggato + // aggiungiamo anche le relative capabilities di basso livello (_foo): + if ($this->organisation_id == $actor->user->organisation_id) $required_capabilities = array_merge($required_capabilities, $required_foo_capabilities); + + if ($actor->user->id != $this->id && !$this->hasCapability($required_capabilities)) return false; + return true; + } + // nessun accesso per actor non di tipo "organizzazione" o "utente": + return false; + } + + /** + * canViewContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canViewContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('view', $actor, $contact_types); + } + + /** + * canAddContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canAddContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('add', $actor, $contact_types); + } + + /** + * canEditContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canEditContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('edit', $actor, $contact_types); + } + + /** + * canDeleteContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canDeleteContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('delete', $actor, $contact_types); + } + + /** + * _getProfiles + * + * @return String + */ + protected function _getProfiles(): String + { + // se la entity è stata appena creata: + if ($this->isNew()) return ""; + + // se non vi è un utente loggato: + $user = Router::getRequest()->getAttribute('identity'); + if (!$user || !$user->hasCapability('configuration.groups.read')) return "**************"; + + $profiles = TableRegistry::getTableLocator()->get('Groups')->find() + ->matching('Users') + ->where(['Users.id' => $this->id]) + ->order(['Groups.description' => 'ASC']) + ->all() + ->extract('description') + ->toArray(); + + return implode(", ", $profiles); + } + + protected function _getMobilePhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('MobilePhones')->find()->contain(['Deliveries', 'MobilePhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->mobile_phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getPhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('Phones')->find()->contain(['Deliveries', 'PhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getEmails() + { + if ($this->isNew()) return []; + $emails = TableRegistry::getTableLocator()->get('Emails')->find()->contain(['Deliveries', 'EmailDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->email_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $emails; + } + + protected function _getPecs() + { + if ($this->isNew()) return []; + $pecs = TableRegistry::getTableLocator()->get('Pecs')->find()->contain(['Deliveries', 'PecDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->pec_description->description, + 'value' => $row->value + ]; + }); + }); + return $pecs; + } + + /** + * __toString + * + * @return String + */ + public function __toString(): String { + if ($this->isNew()) return ""; + $surname = $this->_fields['surname'] ?? ''; + $name = $this->_fields['name'] ?? ''; + $description = "$name $surname"; + + if (isset($this->_fields['organisation_id'])) { + $user_org = TableRegistry::getTableLocator()->get('Organisations')->get($this->_fields['organisation_id'], contain: ['Actors']); + $org_description = $user_org->actor->description ?? null; + if ($org_description) $description .= " ($org_description)"; + } + + return $description; + } + + /** + * canHandleAttachmentsForControllableObject + * + * @param ControllableObject $co + * @return Bool + */ + public function canHandleAttachmentsForControllableObject(ControllableObject $co): Bool + { + return $co->organisation_id == $this->_fields['organisation_id'] || $co->create_user_id = $this->_fields['id']; + } + + /** + * can_view + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_view(User $user, Array &$options): Bool + { + if($user->hasCapability(['configuration.users.read']) || ($user->hasCapability(['configuration.users.read_foo']) && $user->organisation_id == $this->_fields['organisation_id'])) + { + return true; + } else { + if ($user->organisation_id == $this->_fields['organisation_id']) { + $options['error']['capabilities'][] = 'configuration.users.read_foo'; + } + if (empty($options['error']['capabilities'])) { + $options['capabilities'][] = ['configuration.users.read']; + } + return false; + } + } + + /** + * getActor + * + * @return ?Actor + */ + public function getActor(): ?Actor + { + if (!isset($this->_fields['actor_id'])) return null; + return TableRegistry::getTableLocator()->get('Actors')->get($this->_fields['actor_id']); + } + + /** + * hasPushNotificationsWithNotifications + * + * @return Bool + */ + public function hasPushNotificationsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('PushNotifications'); + } + + /** + * hasMobilePhonesWithNotifications + * + * @return Bool + */ + public function hasMobilePhonesWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * hasFaxesWithNotifications + * + * @return Bool + */ + public function hasFaxesWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Faxes'); + } + + /** + * hasEmailsWithNotifications + * + * @return Bool + */ + public function hasEmailsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Emails'); + } + + /** + * hasPecsWithNotifications + * + * @return Bool + */ + public function hasPecsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Pecs'); + } + + /** + * hasTelegramChatsWithNotifications + * + * @return Bool + */ + public function hasTelegramChatsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('TelegramChats'); + } + + /** + * getPushNotificationsWithNotifications + * + * @return Array + */ + public function getPushNotificationsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('PushNotifications'); + } + + /** + * getMobilePhonesWithNotifications + * + * @return Array + */ + public function getMobilePhonesWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * getFaxesWithNotifications + * + * @return Array + */ + public function getFaxesWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Faxes'); + } + + /** + * getEmailsWithNotifications + * + * @return Array + */ + public function getEmailsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Emails'); + } + + /** + * getPecsWithNotifications + * + * @return Array + */ + public function getPecsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Pecs'); + } + + /** + * getTelegramChatsWithNotifications + * + * @return Array + */ + public function getTelegramChatsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('TelegramChats'); + } + + /** + * getDispatchingBitmask + * + * @param ?String $notification_code + * @return ?Int + */ + public function getDispatchingBitmask(?String $notification_code = null): ?Int + { + if (!isset($this->_fields['id'])) return null; + + $bitmask = 0; + + $pushNotificationsCapability = !$notification_code || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.push_notification']); + $mobilePhonesCapability = !$notification_code || $notification_code == "password_recovery" || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.sms']); + $faxesCapability = !$notification_code || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.fax']); + $emailsCapability = !$notification_code || $notification_code == "password_recovery" || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.email']); + $telegramChatsCapability = !$notification_code || $notification_code == "password_recovery" || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.telegram_chat']); + $pecsCapability = $this->hasCapability(['notifications.'.$notification_code.'.pec']); + + if ($pushNotificationsCapability && $this->hasPushNotificationsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(0)->dispatching_bitmask_weight; + if ($mobilePhonesCapability && $this->hasMobilePhonesWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(1)->dispatching_bitmask_weight; + if ($faxesCapability && $this->hasFaxesWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(2)->dispatching_bitmask_weight; + if ($emailsCapability && $this->hasEmailsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(3)->dispatching_bitmask_weight; + if ($telegramChatsCapability && $this->hasTelegramChatsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(4)->dispatching_bitmask_weight; + if ($pecsCapability && $this->hasPecsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(5)->dispatching_bitmask_weight; + + return $bitmask; + } + + protected function _setTaxCode($value) + { + return strtoupper($value); + } + + protected function _getOrganisationProvince(): ?String + { + if (!isset($this->_fields['organisation_id'])) return null; + + if (isset($this->organisation?->province)) { + return $this->organisation->province; + } + + $organisation = TableRegistry::getTableLocator()->get('Organisations') + ->find() + ->select(['province']) + ->where(['id' => $this->_fields['organisation_id']]) + ->first(); + + return $organisation?->province; + } +} diff --git a/idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php b/idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php new file mode 100644 index 0000000..16c7367 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php @@ -0,0 +1,32 @@ +getSource(); + // solo se la entity non è una newEntity (quindi ancora senza repository/source): + if (!empty($source)) { + $user = Router::getRequest()?->getAttribute('identity'); + if (isset($user->disableUserTimezoneDatetimeEntityTrait) && is_bool($user->disableUserTimezoneDatetimeEntityTrait) && $user->disableUserTimezoneDatetimeEntityTrait) return; + $timezone = !empty($user->timezone) ? $user->timezone : Configure::read('App.defaultUserTimezone'); + + $entity_source_schema = TableRegistry::getTableLocator()->get($source)->getSchema(); + foreach ($entity_source_schema->columns() as $entity_property_name) { + $entity_property_type = $entity_source_schema->getColumnType($entity_property_name); + if ($entity_property_type == 'datetime' && isset($this->_fields[$entity_property_name])) { + $this->_fields[$entity_property_name] = $this->_fields[$entity_property_name]?->setTimezone($timezone); + } + } + } + } +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php new file mode 100644 index 0000000..4f4cb10 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'water_drawing_paperwork_id' => true, + 'user_id' => true, + 'water_drawing_antimafia_certification_request_status_id' => true, + 'created' => true, + 'water_drawing_paperwork' => true, + 'user' => true, + 'water_drawing_antimafia_certification_request_status' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php new file mode 100644 index 0000000..3cb87d3 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_antimafia_certification_requests' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingArticle.php b/idrocap_wa/src/Model/Entity/WaterDrawingArticle.php new file mode 100644 index 0000000..12bca94 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingArticle.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'long_description' => true, + 'disable' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php b/idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php new file mode 100644 index 0000000..baf56d2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php @@ -0,0 +1,67 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_body' => true, + 'feature_collection' => true, + 'district' => true, + 'cadastral_code' => true, + 'location' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'latitude' => true, + 'longitude' => true, + 'istat' => true, + 'derivation_status' => true, + 'withdrawals_amount' => true, + 'annual_volume' => true, + 'average_flow_rate' => true, + 'water_drawing_derivation_use_id' => true, + 'water_drawing_derivation_type_id' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_derivation_type' => true, + ]; + + protected array $_hidden = ['geometry']; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php b/idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php new file mode 100644 index 0000000..a7e4462 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_derivations' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingFee.php b/idrocap_wa/src/Model/Entity/WaterDrawingFee.php new file mode 100644 index 0000000..bbe1448 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingFee.php @@ -0,0 +1,65 @@ + + */ + protected array $_accessible = [ + 'amount' => true, + 'year' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_paperwork' => true, + 'water_drawing_payments' => true, + ]; + + protected array $_virtual = [ + 'paied', + 'to_pay', + ]; + + protected function _getPaied(): Bool{ + if(!isset($this->id)) return false; + $total = 0; + $waterDrawingPaymentsTable = TableRegistry::getTableLocator()->get('WaterDrawingPayments'); + $water_drawing_payments = $waterDrawingPaymentsTable->find()->where(['WaterDrawingPayments.water_drawing_fee_id' => $this->id])->toArray(); + foreach($water_drawing_payments as $water_drawing_payment){ + $total += $water_drawing_payment->amount; + } + return ($this->amount <= $total); + } + + protected function _getToPay(): float{ + if(!isset($this->id)) return 0; + $payed = 0; + $waterDrawingPaymentsTable = TableRegistry::getTableLocator()->get('WaterDrawingPayments'); + $water_drawing_payments = $waterDrawingPaymentsTable->find()->where(['WaterDrawingPayments.water_drawing_fee_id' => $this->id])->toArray(); + foreach($water_drawing_payments as $water_drawing_payment){ + $payed = $payed + $water_drawing_payment->amount; + } + return $this->amount - $payed; + } +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php new file mode 100644 index 0000000..5a8759b --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php @@ -0,0 +1,55 @@ + + */ + protected array $_accessible = [ + 'area' => true, + 'cadastral_code' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'consortium_area' => true, + 'rated_power_produced' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_intended_use_type_id' => true, + 'vegetation_match_status' => true, + 'water_drawing_watering_system_id' => true, + 'water_drawing_paperwork' => true, + 'water_drawing_intended_use_type' => true, + 'cadastral_crop_types' => true, + 'water_drawing_meters' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php new file mode 100644 index 0000000..9000d1d --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_intended_uses' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php b/idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php new file mode 100644 index 0000000..a90ccc5 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php @@ -0,0 +1,39 @@ + + */ + protected array $_accessible = [ + 'volume' => true, + 'date' => true, + 'water_drawing_meter_id' => true, + 'user_id' => true, + 'water_drawing_meter' => true, + 'user' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingMeter.php b/idrocap_wa/src/Model/Entity/WaterDrawingMeter.php new file mode 100644 index 0000000..619fc52 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingMeter.php @@ -0,0 +1,45 @@ + + */ + protected array $_accessible = [ + 'water_drawing_tool_type_id' => true, + 'water_drawing_intended_use_id' => true, + 'manufacturer' => true, + 'part_number' => true, + 'installation_date' => true, + 'removal_date' => true, + 'water_drawing_tool_type' => true, + 'water_drawing_measurements' => true, + 'water_drawing_intended_use' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php new file mode 100644 index 0000000..3c6c7f0 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php @@ -0,0 +1,479 @@ + + */ + protected array $_accessible = [ + 'water_drawing_paperwork_status_id' => true, + 'district' => true, + 'location' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'x_coordinate' => true, + 'y_coordinate' => true, + 'istat' => true, + 'derivation_type' => true, + 'derivation_status' => true, + 'withdrawals_amount' => true, + 'annual_volume' => true, + 'average_flow_rate' => true, + 'from_date' => true, + 'to_date' => true, + 'gurs_reference' => true, + 'authorisation_type' => true, + 'concession_decree_number' => true, + 'release_date' => true, + 'concession_duration' => true, + 'expiration_date' => true, + 'first_istance' => true, + 'takeover' => true, + 'year' => true, + 'fee_payment_certificate' => true, + 'initial_static_level_water' => true, + 'initial_static_level_water_date' => true, + 'static_level_water' => true, + 'static_level_water_date' => true, + 'authority_province' => true, + 'authority_identification_code_civil_engineering_office' => true, + 'authority_identification_code_derivation_department_water_waste' => true, + 'water_drawing_article_id' => true, + 'water_drawing_article' => true, + 'water_body' => true, + 'cadastral_code' => true, + 'controllable_object_id' => true, + 'water_drawing_paperwork_status' => true, + 'controllable_object' => true, + 'water_drawing_measurements' => true, + 'applicants' => true, + 'water_drawing_paperwork_histories' => true, + 'attachments' => true, + 'removefiles' => true, + 'feature_collection' => true, + 'geom' => true, + 'scanned' => true, + 'drar_user_id' => true, + 'gc_user_id' => true, + 'water_drawing_antimafia_certification_requests' => true, + 'water_drawing_derivations' => true, + 'water_drawing_return_points' => true, + 'water_drawing_intended_uses' => true, + 'water_drawing_fees' => true, + 'protocol_number' => true, + ]; + + protected array $_virtual = [ + 'water_drawing_paperwork_type_description', + 'authority_civil_engineer_code', + 'check_thc', + 'check_dv', + 'check_lic', + 'check_dec', + 'check_dsc', + 'check2a', + 'check_ssd', + 'check_dam', + 'check_rap', + 'check_ia7', + 'check_ia56', + 'check_ira', + 'check_adam', + 'percentage', + 'check_ram', + 'check_isu', + 'check_rpdi', + 'check_thc_a', + 'check_thc_aa', + 'check_thc_ab', + 'check_thc_ac', + 'check_thc_ad', + 'check_thc_ae', + 'check_thc_af', + 'check_thc_ag', + 'check_thc_b', + 'check_thc_b1', + 'check_thc_b2', + 'check_thc_b3', + 'check_thc_b4', + ]; + + /** + * _getWaterDrawingPaperworkTypeDescription + * + * Virtual Field that returns water_drawing_paperwork description based on the type of instance attachment uploaded + * + * @return string + */ + protected function _getWaterDrawingPaperworkTypeDescription(): string + { + if ($this->_getCheckRap() || $this->_getCheckIa7()) return __('Istanza concessione art. 7'); + if ($this->_getCheckIa56()) return __('Istanza concessione art. 56'); + if ($this->_getCheckIra()) return __('Istanza attingimento art. 30'); + if ($this->_getCheckIsu()) return __('Istanza subentro art. 20'); + if ($this->_getCheckIrc56()) return __('Istanza rinnovo concessione art.56'); + return __(''); + } + + protected function _getAuthorityCivilEngineerCode(): string + { + if (!isset($this->authority_province)) { + return ""; + } + + $sigla = ""; + + switch(strtolower($this->authority_province)){ + case "catania": + $sigla = "CT"; + break; + case "palermo": + $sigla = "PA"; + break; + case "caltanissetta": + $sigla = "CL"; + break; + case "enna": + $sigla = "EN"; + break; + case "ragusa": + $sigla = "RG"; + break; + case "siracusa": + $sigla = "SR"; + break; + case "trapani": + $sigla = "TP"; + break; + case "messina": + $sigla = "ME"; + break; + case "agrigento": + $sigla = "AG"; + break; + default: + $sigla = ""; + } + + return "GC " . $sigla; + } + + protected function _getCheckThc(): Bool{ + return $this->checkDocument(-8); + } + + protected function _getCheckDv(): Bool{ + return $this->checkDocument(-7); + } + + protected function _getCheckLic(): Bool{ + return $this->checkDocument(-6); + } + + protected function _getCheckDec(): Bool{ + return $this->checkDocument(-5); + } + + protected function _getCheckDsc(): Bool{ + return $this->checkDocument(-4); + } + + protected function _getCheck2a(): Bool{ + return $this->checkDocument(-3); + } + + protected function _getCheckSdd(): Bool{ + return $this->checkDocument(-10); + } + + protected function _getCheckDam(): Bool{ + return $this->checkDocument(-11); + } + + protected function _getCheckRap(): Bool{ + return $this->checkDocument(1); + } + + protected function _getCheckIa7(): Bool{ + return $this->checkDocument(2); + } + + protected function _getCheckIa56(): Bool{ + return $this->checkDocument(3); + } + + protected function _getCheckIra(): Bool{ + return $this->checkDocument(4); + } + + protected function _getCheckAdam(): Bool{ + return $this->checkDocument(5); + } + + protected function _getCheckRam(): Bool{ + return $this->checkDocument(-14); + } + + protected function _getCheckIsu(): Bool{ + return $this->checkDocument(6); + } + + protected function _getCheckRpdi(): Bool{ + return $this->checkDocument(-15); + } + + protected function _getCheckThcA(): Bool{ + return $this->checkDocument(7); + } + + protected function _getCheckThcAa(): Bool{ + return $this->checkDocument(8); + } + + protected function _getCheckThcAb(): Bool{ + return $this->checkDocument(9); + } + + protected function _getCheckThcAc(): Bool{ + return $this->checkDocument(10); + } + + protected function _getCheckThcAd(): Bool{ + return $this->checkDocument(11); + } + + protected function _getCheckThcAe(): Bool{ + return $this->checkDocument(12); + } + + protected function _getCheckThcAf(): Bool{ + return $this->checkDocument(13); + } + + protected function _getCheckThcAg(): Bool{ + return $this->checkDocument(14); + } + + protected function _getCheckThcB(): Bool{ + return $this->checkDocument(15); + } + + protected function _getCheckThcB1(): Bool{ + return $this->checkDocument(16); + } + + protected function _getCheckThcB2(): Bool{ + return $this->checkDocument(17); + } + + protected function _getCheckThcB3(): Bool{ + return $this->checkDocument(18); + } + + protected function _getCheckThcB4(): Bool{ + return $this->checkDocument(19); + } + + protected function _getCheckIrc56(): Bool{ + return $this->checkDocument(20); + } + + private function checkDocument($tagId): Bool{ + if(!isset($this->_fields['controllable_object_id'])) return false; + $attachment = TableRegistry::getTableLocator()->get('Attachments')->find()->matching('Tags', function ($q) use ($tagId){ + return $q->where(['Tags.id' => $tagId]); + })->contain(['ControllableObjects']) + ->where(['Attachments.container_controllable_object_id' => $this->_fields['controllable_object_id'], 'ControllableObjects.deleted IS NULL'])->first(); + return isset($attachment); + } + + protected function _getGeom($value) + { + if (!is_string($value) || empty(json_decode($value))) { + return $value; + } + return new QueryExpression("ST_GeomFromGeoJson('$value')"); + } + + protected function _getPercentage() + { + $value = 0; + $fieldsCount = 33; + if(isset($this->_fields['protocol_number'])) $value++; + if(isset($this->_fields['authority_civil_engineer_code'])) $value++; + if(isset($this->_fields['authority_province'])) $value++; + if(isset($this->_fields['authority_identification_code_civil_engineering_office'])) $value++; + if(isset($this->_fields['authority_identification_code_derivation_department_water_waste'])) $value++; + if(isset($this->_fields['water_drawing_article_id'])) $value++; + if(isset($this->_fields['applicants'])) $value++; + if(isset($this->_fields['water_drawing_derivations'])) $value++; + if(isset($this->_fields['water_drawing_intended_uses'])) $value++; + if(isset($this->_fields['water_drawing_return_points'])) $value++; + if(isset($this->_fields['from_date'])) $value++; + if(isset($this->_fields['to_date'])) $value++; + if(isset($this->_fields['gurs_reference'])) $value++; + if(isset($this->_fields['authorisation_type'])) $value++; + if(isset($this->_fields['expiration_date'])) $value++; + if(isset($this->_fields['first_istance'])) $value++; + if(isset($this->_fields['takeover'])) $value++; + if(isset($this->_fields['concession_decree_number'])) $value++; + if(isset($this->_fields['water_drawing_fees'])) $value++; + if(isset($this->_fields['water_drawing_intended_uses']) && isset($this->_fields['water_drawing_intended_uses'][0]['water_drawing_meters'])) $value++; + if(isset($this->_fields['static_level_water'])) $value++; + if(isset($this->_fields['static_level_water_date'])) $value++; + if(isset($this->_fields['initial_static_level_water'])) $value++; + if(isset($this->_fields['initial_static_level_water_date'])) $value++; + if(isset($this->check_thc)) $value++; + if(isset($this->check_dv)) $value++; + if(isset($this->check_lic)) $value++; + if(isset($this->check_dec)) $value++; + if(isset($this->check_dsc)) $value++; + if(isset($this->check_ssd)) $value++; + if(isset($this->check2a)) $value++; + if(isset($this->check_dam)) $value++; + if(isset($this->check_rpdi)) $value++; + return number_format(($value*100)/$fieldsCount, 0, '.','') . '%'; + } + + /** + * is_citizen_documentation_ok_to_send + * + * serve a stabilire se la documentazione minima necessaria per la sottomissione della pratica cittadino è presente oppure no + * + * @return Bool + */ + public function is_citizen_documentation_ok_to_send (): Bool + { + return + $this->_getCheckRpdi() + && + ( + $this->_getCheckIra() + || + $this->_getCheckIsu() + || + $this->_getCheckIrc56() + || + ( + ( + $this->_getCheckRap() + || + $this->_getCheckIa7() + || + $this->_getCheckIa56() + ) + && + $this->_getCheckThcA() + && + $this->_getCheckThcAa() + && + $this->_getCheckThcAb() + && + $this->_getCheckThcAc() + && + $this->_getCheckThcAd() + && + $this->_getCheckThcAe() + && + $this->_getCheckThcB() + && + $this->_getCheckThcB2() + ) + ); + } + + /** + * is_citizen_water_drawing_paperwork_status_ok_to_send + * + * serve a stabilire se lo stato della pratica cittadino è conforme per la sua sottomissione oppure no + * + * @return Bool + */ + public function is_citizen_water_drawing_paperwork_status_ok_to_send (): Bool + { + return in_array($this->_fields['water_drawing_paperwork_status_id'], [8, 11]); + } + + /** + * is_citizen_water_drawing_paperwork_ok_to_send + * + * serve a stabilire se la pratica cittadino è pronta alla sottomissione oppure no + * + * @return Bool + */ + public function is_citizen_water_drawing_paperwork_ok_to_send (): Bool + { + return $this->is_citizen_documentation_ok_to_send() && $this->is_citizen_water_drawing_paperwork_status_ok_to_send(); + } +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php new file mode 100644 index 0000000..42bada6 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php @@ -0,0 +1,54 @@ + + */ + protected array $_accessible = [ + 'result' => true, + 'note' => true, + 'created' => true, + 'user_id' => true, + 'water_drawing_paperwork_id' => true, + 'deleted' => true, + 'water_drawing_paperwork_status_id' => true, + 'controllable_object_id' => true, + 'user' => true, + 'water_drawing_paperwork' => true, + 'water_drawing_paperwork_status' => true, + 'attachments' => true, + 'removefiles' => true, + 'controllable_object' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php new file mode 100644 index 0000000..8533c80 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'water_drawing_paperwork_id' => true, + 'user_id' => true, + 'controllable_object_id' => true, + 'document' => true, + 'protocol_number' => true, + 'protocol_date' => true, + 'recipient' => true, + 'sender' => true, + 'water_drawing_paperwork' => true, + 'user' => true, + 'controllable_object' => true, + 'attachments' => true, + 'removefiles' => true, + 'note' => true + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php new file mode 100644 index 0000000..7f2af0e --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'rgb' => true, + 'water_drawing_paperworks' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPayment.php b/idrocap_wa/src/Model/Entity/WaterDrawingPayment.php new file mode 100644 index 0000000..53d44b6 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPayment.php @@ -0,0 +1,56 @@ + + */ + protected array $_accessible = [ + 'water_drawing_fee_id' => true, + 'water_drawing_payment_type_id' => true, + 'user_id' => true, + 'amount' => true, + 'payment_date' => true, + 'payment_number' => true, + 'notes' => true, + 'created' => true, + 'water_drawing_fee' => true, + 'water_drawing_payment_type' => true, + 'user' => true, + 'receipt_number' => true, + 'receipt_date' => true, + 'receipt_amount' => true, + 'applicant_tax_code' => true + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php new file mode 100644 index 0000000..014a986 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_payments' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php b/idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php new file mode 100644 index 0000000..4a03f2c --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'latitude' => true, + 'longitude' => true, + 'feature_collection' => true, + 'district' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_paperwork' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingToolType.php b/idrocap_wa/src/Model/Entity/WaterDrawingToolType.php new file mode 100644 index 0000000..165ebb6 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingToolType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_meters' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php b/idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php new file mode 100644 index 0000000..4c21c28 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_intended_uses' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Table/ActorTypesTable.php b/idrocap_wa/src/Model/Table/ActorTypesTable.php new file mode 100644 index 0000000..1601834 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ActorTypesTable.php @@ -0,0 +1,81 @@ +setTable('actor_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Actors', [ + 'foreignKey' => 'actor_type_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('entity') + ->maxLength('entity', 255) + ->requirePresence('entity', 'create') + ->notEmptyString('entity'); + + $validator + ->scalar('table') + ->maxLength('table', 255) + ->requirePresence('table', 'create') + ->notEmptyString('table'); + + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ActorsTable.php b/idrocap_wa/src/Model/Table/ActorsTable.php new file mode 100644 index 0000000..fe71589 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ActorsTable.php @@ -0,0 +1,126 @@ +setTable('actors'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ActorTypes', [ + 'foreignKey' => 'actor_type_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('Deliveries', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Groups', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Organisations', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Users', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->integer('actor_type_id') + ->requirePresence('actor_type_id', 'create') + ->notEmptyString('actor_type_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_type_id', 'ActorTypes'), ['errorField' => 'actor_type_id']); + $rules->addDelete(function ($entity, $options) { + // mi assicuro che l'actor è di tipo Groups + if($entity->actor_type_id == 6) { + $group = $this->Groups->find()->where(['actor_id' => $entity->id])->first(); + if(isset($group) && !$group->is_editable) { + return false; + } + } + return true; + }, 'checkGroupIsEditable', ['errorField' => 'is_editable', 'message' => __('Questo profilo non può essere eliminato.')]); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/ApplicantsTable.php b/idrocap_wa/src/Model/Table/ApplicantsTable.php new file mode 100644 index 0000000..ab210f6 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ApplicantsTable.php @@ -0,0 +1,208 @@ +setTable('applicants'); + $this->setDisplayField('name'); + $this->setPrimaryKey('id'); + + $this->hasMany('ApplicantsWaterDrawingPaperworks', [ + 'foreignKey' => 'applicant_id', + ]); + $this->belongsToMany('WaterDrawingPaperworks', [ + 'foreignKey' => 'applicant_id', + 'targetForeignKey' => 'water_drawing_paperwork_id', + 'joinTable' => 'applicants_water_drawing_paperworks', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('name') + ->maxLength('name', 255) + ->allowEmptyString('name'); + + $validator + ->scalar('surname') + ->maxLength('surname', 255) + ->allowEmptyString('surname'); + + $validator + ->scalar('company_name') + ->maxLength('company_name', 255) + ->allowEmptyString('company_name'); + + $validator + ->scalar('tax_code') + ->maxLength('tax_code', 255) + ->allowEmptyString('tax_code') + ->regex('tax_code', '/^[A-Z]{6}[0-9LMNPQRSTUV]{2}[A-EHLMPR-T]{1}[0-9LMNPQRSTUV]{2}[A-Z]{1}[0-9LMNPQRSTUV]{3}[A-Z]{1}$/', 'Il formato del codice fiscale è errato.'); + + $validator + ->scalar('vat_number') + ->maxLength('vat_number', 255) + ->allowEmptyString('vat_number'); + + $validator + ->scalar('address') + ->maxLength('address', 255) + ->allowEmptyString('address'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->allowEmptyString('district'); + + $validator + ->scalar('province') + ->maxLength('province', 255) + ->allowEmptyString('province'); + + $validator + ->scalar('pec_address') + ->email('pec_address', true) + ->maxLength('pec_address', 255) + ->allowEmptyString('pec_address'); + + $validator + ->scalar('email_address') + ->maxLength('email_address', 255) + ->allowEmptyString('email_address'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['tax_code', 'deleted'], __('Un richiedente con lo stesso codice fiscale è già presente!')), ['errorField' => 'tax_code']); + + $rules->add(function ($entity, $options) { + $districtsTable = $this->fetchTable("Districts"); + + if (!empty($entity->district)) { + $exists = $districtsTable->exists(['comune' => $entity->district]); + if (!$exists) { + return false; + } + } + + return true; + }, 'validDistrict', [ + 'errorField' => 'district', + 'message' => 'Il comune selezionato non è valido.' + ]); + + $rules->add(function ($entity, $options) { + $countiesTable = $this->fetchTable("Counties"); + + if (!empty($entity->province)) { + $provinceField = strlen($entity->province) === 2 ? 'sigla' : 'den_uts'; + $exists = $countiesTable->exists([$provinceField => $entity->province]); + if (!$exists) { + return false; + } + } + + return true; + }, 'validProvince', [ + 'errorField' => 'province', + 'message' => 'La provincia selezionata non è valida.' + ]); + + return $rules; + } + + public function beforeMarshal( $event, $data, $options) + { + if (isset($data['tax_code'])) { + $data['tax_code'] = strtoupper($data['tax_code']); + } + if (isset($data['province'])) { + switch (strtolower($data['province'])) { + case 'catania': + $data['province'] = 'CT'; + break; + case 'palermo': + $data['province'] = 'PA'; + break; + case 'caltanissetta': + $data['province'] = 'CL'; + break; + case 'enna': + $data['province'] = 'EN'; + break; + case 'ragusa': + $data['province'] = 'RG'; + break; + case 'siracusa': + $data['province'] = 'SR'; + break; + case 'trapani': + $data['province'] = 'TP'; + break; + case 'messina': + $data['province'] = 'ME'; + break; + case 'agrigento': + $data['province'] = 'AG'; + break; + } + } + } +} diff --git a/idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php b/idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php new file mode 100644 index 0000000..d467201 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php @@ -0,0 +1,100 @@ +setTable('applicants_water_drawing_paperworks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Applicants', [ + 'foreignKey' => 'applicant_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('applicant_id') + ->notEmptyString('applicant_id'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->allowEmptyString('is_primary_applicant'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('applicant_id', 'Applicants'), ['errorField' => 'applicant_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add(function ($entity){ + $result = $this->find()->where([ + 'ApplicantsWaterDrawingPaperworks.applicant_id' => $entity->applicant_id, + 'ApplicantsWaterDrawingPaperworks.water_drawing_paperwork_id' => $entity->water_drawing_paperwork_id]) + ->count(); + return $result <= 1; + }, ['errorField' => 'applicant_id', 'message' => __('Questo richiedente è già presente all\'interno della pratica.')]); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/AttachmentsTable.php b/idrocap_wa/src/Model/Table/AttachmentsTable.php new file mode 100644 index 0000000..6283be7 --- /dev/null +++ b/idrocap_wa/src/Model/Table/AttachmentsTable.php @@ -0,0 +1,133 @@ +setTable('attachments'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ContainerControllableObjects', [ + 'className' => 'ControllableObjects', + 'foreignKey' => 'container_controllable_object_id', + 'joinType' => 'INNER', + ]); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsToMany('Tags', [ + 'foreignKey' => 'attachment_id', + 'targetForeignKey' => 'tag_id', + 'joinTable' => 'attachments_tags', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('original_file_name') + ->maxLength('original_file_name', 255) + ->requirePresence('original_file_name', 'create') + ->notEmptyFile('original_file_name'); + + $validator + ->integer('original_file_size') + ->requirePresence('original_file_size', 'create') + ->notEmptyFile('original_file_size'); + + $validator + ->scalar('file_name') + ->maxLength('file_name', 255) + ->requirePresence('file_name', 'create') + ->notEmptyFile('file_name'); + + $validator + ->scalar('mimetype') + ->maxLength('mimetype', 255) + ->requirePresence('mimetype', 'create') + ->notEmptyString('mimetype'); + + $validator + ->dateTime('upload_date') + ->requirePresence('upload_date', 'create') + ->notEmptyDateTime('upload_date'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->integer('container_controllable_object_id') + ->allowEmptyString('container_controllable_object_id'); + + $validator + ->boolean('relevant') + ->allowEmptyString('relevant'); + + $validator + ->boolean('private') + ->notEmptyString('private'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/BackgroundTasksTable.php b/idrocap_wa/src/Model/Table/BackgroundTasksTable.php new file mode 100644 index 0000000..f87ea46 --- /dev/null +++ b/idrocap_wa/src/Model/Table/BackgroundTasksTable.php @@ -0,0 +1,103 @@ +setTable('background_tasks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->hasMany('DispatchingTasks', [ + 'foreignKey' => 'background_task_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('command') + ->maxLength('command', 4294967295) + ->requirePresence('command', 'create') + ->notEmptyString('command'); + + $validator + ->scalar('data') + ->maxLength('data', 4294967295) + ->requirePresence('data', 'create') + ->notEmptyString('data'); + + $validator + ->scalar('dgroup') + ->maxLength('dgroup', 255) + ->allowEmptyString('dgroup') + ->add('dgroup', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->integer('status') + ->notEmptyString('status'); + + $validator + ->notEmptyString('was_synced'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['dgroup'], ['allowMultipleNulls' => true]), ['errorField' => 'dgroup']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CadastralCropTypesTable.php b/idrocap_wa/src/Model/Table/CadastralCropTypesTable.php new file mode 100644 index 0000000..cd1d133 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CadastralCropTypesTable.php @@ -0,0 +1,69 @@ +setTable('cadastral_crop_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsToMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'cadastral_crop_type_id', + 'targetForeignKey' => 'water_drawing_intended_use_id', + 'joinTable' => 'cadastral_crop_types_water_drawing_intended_uses', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php b/idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php new file mode 100644 index 0000000..1b064d3 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php @@ -0,0 +1,91 @@ +setTable('capabilities_menu_items'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Capabilities', [ + 'foreignKey' => 'capability_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('MenuItems', [ + 'foreignKey' => 'menu_item_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('capability_id') + ->requirePresence('capability_id', 'create') + ->notEmptyString('capability_id'); + + $validator + ->integer('menu_item_id') + ->requirePresence('menu_item_id', 'create') + ->notEmptyString('menu_item_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_id', 'Capabilities'), ['errorField' => 'capability_id']); + $rules->add($rules->existsIn('menu_item_id', 'MenuItems'), ['errorField' => 'menu_item_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php b/idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php new file mode 100644 index 0000000..2b40932 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php @@ -0,0 +1,91 @@ +setTable('capabilities_menu_sections'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Capabilities', [ + 'foreignKey' => 'capability_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('MenuSections', [ + 'foreignKey' => 'menu_section_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('capability_id') + ->requirePresence('capability_id', 'create') + ->notEmptyString('capability_id'); + + $validator + ->integer('menu_section_id') + ->requirePresence('menu_section_id', 'create') + ->notEmptyString('menu_section_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_id', 'Capabilities'), ['errorField' => 'capability_id']); + $rules->add($rules->existsIn('menu_section_id', 'MenuSections'), ['errorField' => 'menu_section_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilitiesTable.php b/idrocap_wa/src/Model/Table/CapabilitiesTable.php new file mode 100644 index 0000000..d218875 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilitiesTable.php @@ -0,0 +1,145 @@ +setTable('capabilities'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('CapabilityGroups', [ + 'foreignKey' => 'capability_group_id', + 'joinType' => 'INNER', + ]); + $this->belongsToMany('Groups', [ + 'foreignKey' => 'capability_id', + 'targetForeignKey' => 'group_id', + 'joinTable' => 'permissions', + ]); + $this->belongsToMany('MenuItems', [ + 'foreignKey' => 'capability_id', + 'targetForeignKey' => 'menu_item_id', + 'joinTable' => 'capabilities_menu_items', + ]); + $this->belongsToMany('MenuSections', [ + 'foreignKey' => 'capability_id', + 'targetForeignKey' => 'menu_section_id', + 'joinTable' => 'capabilities_menu_sections', + ]); + $this->hasMany('Permissions', [ + 'foreignKey' => 'capability_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value'); + + $validator + ->integer('priority') + ->notEmptyString('priority'); + + $validator + ->integer('capability_group_id') + ->requirePresence('capability_group_id', 'create') + ->notEmptyString('capability_group_id'); + + $validator + ->integer('priority_group_id') + ->allowEmptyString('priority_group_id'); + + $validator + ->boolean('organisation_required') + ->notEmptyString('organisation_required'); + + $validator + ->scalar('longdescription') + ->maxLength('longdescription', 4294967295) + ->allowEmptyString('longdescription'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->boolean('is_configurable') + ->notEmptyString('is_configurable'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_group_id', 'CapabilityGroups'), ['errorField' => 'capability_group_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilityGroupsTable.php b/idrocap_wa/src/Model/Table/CapabilityGroupsTable.php new file mode 100644 index 0000000..a517cb5 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilityGroupsTable.php @@ -0,0 +1,79 @@ +setTable('capability_groups'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('Capabilities', [ + 'foreignKey' => 'capability_group_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->boolean('is_configurable') + ->notEmptyString('is_configurable'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php b/idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php new file mode 100644 index 0000000..3375fb0 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php @@ -0,0 +1,77 @@ +setTable('controllable_object_interface_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('ControllableObjectInterfaces', [ + 'foreignKey' => 'controllable_object_interface_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('entity') + ->maxLength('entity', 255) + ->requirePresence('entity', 'create') + ->notEmptyString('entity'); + + $validator + ->scalar('table') + ->maxLength('table', 255) + ->requirePresence('table', 'create') + ->notEmptyString('table'); + + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php b/idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php new file mode 100644 index 0000000..5b08d1b --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php @@ -0,0 +1,95 @@ +setTable('controllable_object_interfaces'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjectInterfaceTypes', [ + 'foreignKey' => 'controllable_object_interface_type_id', + 'joinType' => 'INNER', + ]); + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = -1; + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->integer('controllable_object_interface_type_id') + ->notEmptyString('controllable_object_interface_type_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('controllable_object_interface_type_id', 'ControllableObjectInterfaceTypes'), ['errorField' => 'controllable_object_interface_type_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php b/idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php new file mode 100644 index 0000000..2cdcc31 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php @@ -0,0 +1,74 @@ +setTable('controllable_object_types'); + $this->setDisplayField('label'); + $this->setPrimaryKey('id'); + + $this->hasMany('ControllableObjects', [ + 'foreignKey' => 'controllable_object_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 45) + ->allowEmptyString('description'); + + $validator + ->scalar('controller') + ->maxLength('controller', 45) + ->allowEmptyString('controller'); + + $validator + ->scalar('label') + ->maxLength('label', 255) + ->allowEmptyString('label'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectsTable.php b/idrocap_wa/src/Model/Table/ControllableObjectsTable.php new file mode 100644 index 0000000..aaf1747 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectsTable.php @@ -0,0 +1,167 @@ +setTable('controllable_objects'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Organisations', [ + 'foreignKey' => 'organisation_id', + ]); + $this->belongsTo('ControllableObjectTypes', [ + 'foreignKey' => 'controllable_object_type_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('ChildAttachments', [ + 'className' => 'Attachments', + 'foreignKey' => 'container_controllable_object_id', + 'joinType' => 'LEFT', + ]); + $this->hasMany('Attachments', [ + 'foreignKey' => 'controllable_object_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('ControllableObjectInterfaces', [ + 'foreignKey' => 'controllable_object_id', + ]); + $this->belongsTo('Creator', [ + 'foreignKey' => 'create_user_id', + 'className' => 'Users', + 'joinType' => 'LEFT' + ]); + $this->belongsTo('Modifier', [ + 'foreignKey' => 'edit_user_id', + 'className' => 'Users', + 'joinType' => 'LEFT' + ]); + $this->hasOne('Locations', [ + 'foreignKey' => 'controllable_object_id', + ]); + + $this->hasOne('WaterDrawingPaperworks', [ + 'foreignKey' => 'controllable_object_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->hasOne('WaterDrawingPaperworkPecs', [ + 'foreignKey' => 'controllable_object_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('organisation_id') + ->allowEmptyString('organisation_id'); + + $validator + ->integer('controllable_object_type_id') + ->requirePresence('controllable_object_type_id', 'create') + ->notEmptyString('controllable_object_type_id'); + + $validator + ->integer('create_user_id') + ->allowEmptyString('create_user_id'); + + $validator + ->integer('edit_user_id') + ->allowEmptyString('edit_user_id'); + + $validator + ->integer('edit_organisation_id') + ->allowEmptyString('edit_organisation_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('organisation_id', 'Organisations'), ['errorField' => 'organisation_id']); + $rules->add($rules->existsIn('controllable_object_type_id', 'ControllableObjectTypes'), ['errorField' => 'controllable_object_type_id']); + $rules->add($rules->existsIn('create_user_id', 'Creator'), ['errorField' => 'create_user_id']); + $rules->add($rules->existsIn('edit_user_id', 'Modifier'), ['errorField' => 'edit_user_id']); + $rules->add($rules->existsIn('edit_organisation_id', 'Organisations'), ['errorField' => 'edit_organisation_id']); + + return $rules; + } + + public function beforeSave(EventInterface $event, ControllableObject $entity, \ArrayObject $options) + { + $user = Router::getRequest()?->getAttribute('identity'); + if (!isset($entity->id)) $entity->organisation_id = $user->organisation_id ?? null; + if (!isset($entity->id)) $entity->create_user_id = $user->id ?? null; + $entity->edit_user_id = $user->id ?? null; + $entity->edit_organisation_id = $user->organisation_id ?? null; + } +} diff --git a/idrocap_wa/src/Model/Table/CountiesTable.php b/idrocap_wa/src/Model/Table/CountiesTable.php new file mode 100644 index 0000000..449369c --- /dev/null +++ b/idrocap_wa/src/Model/Table/CountiesTable.php @@ -0,0 +1,165 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\County get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\County findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\County patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\County> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\County|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\County saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County> deleteManyOrFail(iterable $entities, array $options = []) + */ +class CountiesTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('counties'); + $this->setDisplayField('OGR_FID'); + $this->setPrimaryKey('OGR_FID'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->requirePresence('SHAPE', 'create') + ->notEmptyString('SHAPE'); + + $validator + ->decimal('cod_rip') + ->allowEmptyString('cod_rip'); + + $validator + ->decimal('cod_reg') + ->allowEmptyString('cod_reg'); + + $validator + ->decimal('cod_prov') + ->allowEmptyString('cod_prov'); + + $validator + ->decimal('cod_cm') + ->allowEmptyString('cod_cm'); + + $validator + ->decimal('cod_uts') + ->allowEmptyString('cod_uts'); + + $validator + ->scalar('den_prov') + ->maxLength('den_prov', 50) + ->allowEmptyString('den_prov'); + + $validator + ->scalar('den_cm') + ->maxLength('den_cm', 50) + ->allowEmptyString('den_cm'); + + $validator + ->scalar('den_uts') + ->maxLength('den_uts', 50) + ->allowEmptyString('den_uts'); + + $validator + ->scalar('sigla') + ->maxLength('sigla', 2) + ->allowEmptyString('sigla'); + + $validator + ->scalar('tipo_uts') + ->maxLength('tipo_uts', 50) + ->allowEmptyString('tipo_uts'); + + $validator + ->scalar('shape_leng') + ->maxLength('shape_leng', 255) + ->allowEmptyString('shape_leng'); + + $validator + ->scalar('shape_area') + ->maxLength('shape_area', 255) + ->allowEmptyString('shape_area'); + + return $validator; + } + + public function getCountiesByRegion(int $cod_reg, ProvinceCellDto $provinceCellConfig): array + { + $provinceFullNameField = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::FULL_NAME); + $provinceSiglaField = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::ABBREVIATION); + $provinceCodeValueField = $provinceCellConfig->showProvinceFullName ? $provinceFullNameField : $provinceSiglaField; + + $provinceCodeField = ProvinceDistrictFieldHelper::forCounties(ProvinceDistrictFields::PROVINCE_CODE); + $regionCodeField = ProvinceDistrictFieldHelper::forCounties(ProvinceDistrictFields::REGION_CODE); + + $results = $this->find() + ->select([$provinceCodeField, $provinceCodeValueField]) + ->where([$regionCodeField => $cod_reg]) + ->all() + ->toArray(); + + $options = Hash::combine($results, '{n}.' . $provinceCodeValueField, '{n}.' . $provinceCodeValueField); + $map = Hash::combine($results, '{n}.' . $provinceCodeValueField, '{n}.' . ProvinceDistrictFields::PROVINCE_CODE->value); + + return [ + "options" => $options, + "map" => $map, + ]; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['OGR_FID']), ['errorField' => 'OGR_FID']); + + return $rules; + } + + /** + * Returns the database connection name to use by default. + * + * @return string + */ + public static function defaultConnectionName(): string + { + return 'geo'; + } +} diff --git a/idrocap_wa/src/Model/Table/DeliveriesTable.php b/idrocap_wa/src/Model/Table/DeliveriesTable.php new file mode 100644 index 0000000..4929f7f --- /dev/null +++ b/idrocap_wa/src/Model/Table/DeliveriesTable.php @@ -0,0 +1,145 @@ +setTable('deliveries'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('DeliveryTypes', [ + 'foreignKey' => 'delivery_type_id', + 'joinType' => 'INNER', + ]); + $this->hasOne('Emails', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Faxes', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('MobilePhones', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Phones', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('PushNotifications', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('TelegramChats', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('TelegramContacts', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Pecs', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('actor_id') + ->requirePresence('actor_id', 'create') + ->notEmptyString('actor_id'); + + $validator + ->integer('delivery_type_id') + ->requirePresence('delivery_type_id', 'create') + ->notEmptyString('delivery_type_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + $rules->add($rules->existsIn('delivery_type_id', 'DeliveryTypes'), ['errorField' => 'delivery_type_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/DeliveryTypesTable.php b/idrocap_wa/src/Model/Table/DeliveryTypesTable.php new file mode 100644 index 0000000..730e61d --- /dev/null +++ b/idrocap_wa/src/Model/Table/DeliveryTypesTable.php @@ -0,0 +1,65 @@ +setTable('delivery_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Deliveries', [ + 'foreignKey' => 'delivery_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php b/idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php new file mode 100644 index 0000000..d26676e --- /dev/null +++ b/idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php @@ -0,0 +1,111 @@ +setTable('dispatching_task_items'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('DispatchingTasks', [ + 'foreignKey' => 'dispatching_task_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('dispatching_task_id') + ->requirePresence('dispatching_task_id', 'create') + ->notEmptyString('dispatching_task_id'); + + $validator + ->integer('actor_id') + ->requirePresence('actor_id', 'create') + ->notEmptyString('actor_id'); + + $validator + ->boolean('system_dispatched') + ->allowEmptyString('system_dispatched'); + + $validator + ->integer('actor_dispatching_bitmask') + ->notEmptyString('actor_dispatching_bitmask'); + + $validator + ->integer('performed_dispatching_bitmask') + ->notEmptyString('performed_dispatching_bitmask'); + + $validator + ->integer('not_performed_dispatching_bitmask') + ->allowEmptyString('not_performed_dispatching_bitmask'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('dispatching_task_id', 'DispatchingTasks'), ['errorField' => 'dispatching_task_id']); + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php b/idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php new file mode 100644 index 0000000..f911aa3 --- /dev/null +++ b/idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php @@ -0,0 +1,65 @@ +setTable('dispatching_task_statuses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('DispatchingTasks', [ + 'foreignKey' => 'dispatching_task_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/DispatchingTasksTable.php b/idrocap_wa/src/Model/Table/DispatchingTasksTable.php new file mode 100644 index 0000000..3f5d008 --- /dev/null +++ b/idrocap_wa/src/Model/Table/DispatchingTasksTable.php @@ -0,0 +1,113 @@ +setTable('dispatching_tasks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('DispatchingTaskStatuses', [ + 'foreignKey' => 'dispatching_task_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('BackgroundTasks', [ + 'foreignKey' => 'background_task_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('DispatchingTaskItems', [ + 'foreignKey' => 'dispatching_task_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('dispatching_task_group') + ->maxLength('dispatching_task_group', 255) + ->requirePresence('dispatching_task_group', 'create') + ->notEmptyString('dispatching_task_group'); + + $validator + ->integer('dispatching_task_status_id') + ->requirePresence('dispatching_task_status_id', 'create') + ->notEmptyString('dispatching_task_status_id'); + + $validator + ->integer('retries') + ->notEmptyString('retries'); + + $validator + ->boolean('failed') + ->notEmptyString('failed'); + + $validator + ->integer('background_task_id') + ->requirePresence('background_task_id', 'create') + ->notEmptyString('background_task_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('dispatching_task_status_id', 'DispatchingTaskStatuses'), ['errorField' => 'dispatching_task_status_id']); + $rules->add($rules->existsIn('background_task_id', 'BackgroundTasks'), ['errorField' => 'background_task_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/DistrictsTable.php b/idrocap_wa/src/Model/Table/DistrictsTable.php new file mode 100644 index 0000000..23dec60 --- /dev/null +++ b/idrocap_wa/src/Model/Table/DistrictsTable.php @@ -0,0 +1,136 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\District get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\District findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\District patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\District> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\District|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\District saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District> deleteManyOrFail(iterable $entities, array $options = []) + */ +class DistrictsTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('districts'); + $this->setDisplayField('OGR_FID'); + $this->setPrimaryKey('OGR_FID'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->requirePresence('SHAPE', 'create') + ->notEmptyString('SHAPE'); + + $validator + ->decimal('cod_rip') + ->allowEmptyString('cod_rip'); + + $validator + ->decimal('cod_reg') + ->allowEmptyString('cod_reg'); + + $validator + ->decimal('cod_prov') + ->allowEmptyString('cod_prov'); + + $validator + ->decimal('cod_cm') + ->allowEmptyString('cod_cm'); + + $validator + ->decimal('cod_uts') + ->allowEmptyString('cod_uts'); + + $validator + ->decimal('pro_com') + ->allowEmptyString('pro_com'); + + $validator + ->scalar('pro_com_t') + ->maxLength('pro_com_t', 6) + ->allowEmptyString('pro_com_t'); + + $validator + ->scalar('comune') + ->maxLength('comune', 100) + ->allowEmptyString('comune'); + + $validator + ->scalar('comune_a') + ->maxLength('comune_a', 100) + ->allowEmptyString('comune_a'); + + $validator + ->decimal('cc_uts') + ->allowEmptyString('cc_uts'); + + $validator + ->scalar('shape_leng') + ->maxLength('shape_leng', 255) + ->allowEmptyString('shape_leng'); + + $validator + ->scalar('shape_area') + ->maxLength('shape_area', 255) + ->allowEmptyString('shape_area'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['OGR_FID']), ['errorField' => 'OGR_FID']); + + return $rules; + } + + /** + * Returns the database connection name to use by default. + * + * @return string + */ + public static function defaultConnectionName(): string + { + return 'geo'; + } +} diff --git a/idrocap_wa/src/Model/Table/EmailDescriptionsTable.php b/idrocap_wa/src/Model/Table/EmailDescriptionsTable.php new file mode 100644 index 0000000..30b921a --- /dev/null +++ b/idrocap_wa/src/Model/Table/EmailDescriptionsTable.php @@ -0,0 +1,74 @@ +setTable('email_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Emails', [ + 'foreignKey' => 'email_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/EmailsTable.php b/idrocap_wa/src/Model/Table/EmailsTable.php new file mode 100644 index 0000000..ccff182 --- /dev/null +++ b/idrocap_wa/src/Model/Table/EmailsTable.php @@ -0,0 +1,111 @@ +setTable('emails'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('EmailDescriptions', [ + 'foreignKey' => 'email_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->email('value', true); + + $validator + ->boolean('is_system') + ->notEmptyString('is_system'); + + $validator + ->boolean('enable_notifications') + ->notEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('email_description_id') + ->requirePresence('email_description_id', 'create') + ->allowEmptyString('email_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('email_description_id', 'EmailDescriptions'), ['errorField' => 'email_description_id']); + $rules->add($rules->isUnique(['value'], __('Indirizzo email già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/FaxDescriptionsTable.php b/idrocap_wa/src/Model/Table/FaxDescriptionsTable.php new file mode 100644 index 0000000..9daf8fb --- /dev/null +++ b/idrocap_wa/src/Model/Table/FaxDescriptionsTable.php @@ -0,0 +1,73 @@ +setTable('fax_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Faxes', [ + 'foreignKey' => 'fax_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/FaxesTable.php b/idrocap_wa/src/Model/Table/FaxesTable.php new file mode 100644 index 0000000..63bac03 --- /dev/null +++ b/idrocap_wa/src/Model/Table/FaxesTable.php @@ -0,0 +1,107 @@ +setTable('faxes'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('FaxDescriptions', [ + 'foreignKey' => 'fax_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->regex('value', '/^[0-9]*$/i'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('fax_description_id') + ->requirePresence('fax_description_id', 'create') + ->allowEmptyString('fax_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('fax_description_id', 'FaxDescriptions'), ['errorField' => 'fax_description_id']); + $rules->add($rules->isUnique(['value'], __('Fax già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/FiltersTable.php b/idrocap_wa/src/Model/Table/FiltersTable.php new file mode 100644 index 0000000..37e9521 --- /dev/null +++ b/idrocap_wa/src/Model/Table/FiltersTable.php @@ -0,0 +1,105 @@ +setTable('filters'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('controller_action_category') + ->maxLength('controller_action_category', 255) + ->requirePresence('controller_action_category', 'create') + ->notEmptyString('controller_action_category'); + + $validator + ->scalar('category') + ->maxLength('category', 255) + ->requirePresence('category', 'create') + ->notEmptyString('category'); + + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('filter_type') + ->maxLength('filter_type', 255) + ->requirePresence('filter_type', 'create') + ->notEmptyString('filter_type'); + + $validator + ->scalar('class_name') + ->maxLength('class_name', 255) + ->allowEmptyString('class_name'); + + $validator + ->scalar('search') + ->maxLength('search', 255) + ->allowEmptyString('search'); + + $validator + ->scalar('associations') + ->maxLength('associations', 255) + ->allowEmptyString('associations'); + + $validator + ->integer('order_number') + ->requirePresence('order_number', 'create') + ->notEmptyString('order_number'); + + $validator + ->boolean('sys_admin_only') + ->allowEmptyString('sys_admin_only'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/GroupsGroupsTable.php b/idrocap_wa/src/Model/Table/GroupsGroupsTable.php new file mode 100644 index 0000000..831c287 --- /dev/null +++ b/idrocap_wa/src/Model/Table/GroupsGroupsTable.php @@ -0,0 +1,94 @@ +setTable('groups_groups'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ContainerGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'container_group_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ContainedGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'group_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('container_group_id') + ->requirePresence('container_group_id', 'create') + ->notEmptyString('container_group_id'); + + $validator + ->integer('group_id') + ->requirePresence('group_id', 'create') + ->notEmptyString('group_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('container_group_id', 'Groups'), ['errorField' => 'container_group_id']); + $rules->add($rules->existsIn('group_id', 'Groups'), ['errorField' => 'group_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/GroupsTable.php b/idrocap_wa/src/Model/Table/GroupsTable.php new file mode 100644 index 0000000..c6b0bfa --- /dev/null +++ b/idrocap_wa/src/Model/Table/GroupsTable.php @@ -0,0 +1,157 @@ +setTable('groups'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('Memberships', [ + 'foreignKey' => 'group_id', + ]); + $this->hasMany('Permissions', [ + 'foreignKey' => 'group_id', + ]); + $this->belongsToMany('Users', [ + 'foreignKey' => 'group_id', + 'targetForeignKey' => 'user_id', + 'joinTable' => 'memberships', + ]); + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'group_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'permissions', + ]); + + $this->belongsToMany('ChildGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'container_group_id', + 'targetForeignKey' => 'group_id', + 'joinTable' => 'groups_groups', + 'sort' => 'description ASC' + ]); + + $this->belongsToMany('ParentGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'group_id', + 'targetForeignKey' => 'container_group_id', + 'joinTable' => 'groups_groups', + 'sort' => 'description ASC' + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->boolean('is_default') + ->allowEmptyString('is_default'); + + $validator + ->boolean('super_group') + ->allowEmptyString('super_group'); + + $validator + ->integer('actor_id') + ->notEmptyString('actor_id') + ->add('actor_id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + return $validator; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['actor']['actor_type_id'] = 6; + $data['actor']['description'] = $data['description']; + + if (isset($options['group_id']) && isset($data['capabilities']['_ids'])) { + $user = Router::getRequest()->getAttribute('identity'); + if (!$user || !$user->sys_admin) { + $not_configurable_capability_ids = TableRegistry::getTableLocator()->get('Capabilities') + ->find() + ->matching('Permissions') + ->select(['Capabilities.id']) + ->where(['Permissions.group_id' => $options['group_id'], 'OR' => ['Capabilities.is_configurable IS NULL', 'Capabilities.is_configurable' => 0]]) + ->all() + ->extract('id') + ->toArray(); + + $data['capabilities']['_ids'] = array_merge($data['capabilities']['_ids'], $not_configurable_capability_ids); + } + } + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/LanguagesTable.php b/idrocap_wa/src/Model/Table/LanguagesTable.php new file mode 100644 index 0000000..dc7edfa --- /dev/null +++ b/idrocap_wa/src/Model/Table/LanguagesTable.php @@ -0,0 +1,71 @@ +setTable('languages'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 45) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('language_code') + ->maxLength('language_code', 45) + ->requirePresence('language_code', 'create') + ->notEmptyString('language_code'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/LocationAttributesTable.php b/idrocap_wa/src/Model/Table/LocationAttributesTable.php new file mode 100644 index 0000000..e77a8b2 --- /dev/null +++ b/idrocap_wa/src/Model/Table/LocationAttributesTable.php @@ -0,0 +1,116 @@ +setTable('location_attributes'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Locations', [ + 'foreignKey' => 'location_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('location_id') + ->requirePresence('location_id', 'create') + ->notEmptyString('location_id'); + + $validator + ->scalar('district_code') + ->maxLength('district_code', 255) + ->requirePresence('district_code', 'create') + ->notEmptyString('district_code'); + + $validator + ->scalar('district_name') + ->maxLength('district_name', 255) + ->requirePresence('district_name', 'create') + ->notEmptyString('district_name'); + + $validator + ->scalar('county_code') + ->maxLength('county_code', 255) + ->requirePresence('county_code', 'create') + ->notEmptyString('county_code'); + + $validator + ->scalar('county_name') + ->maxLength('county_name', 255) + ->requirePresence('county_name', 'create') + ->notEmptyString('county_name'); + + $validator + ->scalar('region') + ->maxLength('region', 255) + ->requirePresence('region', 'create') + ->notEmptyString('region'); + + $validator + ->scalar('area') + ->maxLength('area', 255) + ->requirePresence('area', 'create') + ->notEmptyString('area'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('location_id', 'Locations'), ['errorField' => 'location_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/LocationsTable.php b/idrocap_wa/src/Model/Table/LocationsTable.php new file mode 100644 index 0000000..22bcfa8 --- /dev/null +++ b/idrocap_wa/src/Model/Table/LocationsTable.php @@ -0,0 +1,118 @@ +setTable('locations'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + ]); + $this->hasMany('LocationAttributes', [ + 'foreignKey' => 'location_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('coordinates') + ->maxLength('coordinates', 4294967295) + ->allowEmptyString('coordinates'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('geom') + ->allowEmptyString('geom'); + + $validator + ->integer('controllable_object_id') + ->allowEmptyString('controllable_object_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + return $rules; + } + + public function beforeSave(EventInterface $event, Location $entity, \ArrayObject $options) + { + $locationAttributesTable = TableRegistry::getTableLocator()->get('LocationAttributes'); + $lar = new LocationAttributesRetriever($entity); + if (isset($entity->id)) { + $locationAttributesTable->deleteAll(['LocationAttributes.location_id' => $entity->id]); + } + $lar_result = $lar->retrieve(); + if (isset($lar_result['error']) && $lar_result['error']) { + throw new \Exception($lar_result['message']); + } + $entity->location_attributes = $locationAttributesTable->newEntities($lar_result); + } +} diff --git a/idrocap_wa/src/Model/Table/MapsTable.php b/idrocap_wa/src/Model/Table/MapsTable.php new file mode 100644 index 0000000..69b273c --- /dev/null +++ b/idrocap_wa/src/Model/Table/MapsTable.php @@ -0,0 +1,88 @@ +setTable('maps'); + $this->setDisplayField('name'); + $this->setPrimaryKey(['id', 'language_code']); + + $this->addBehavior('Timestamp'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('code') + ->maxLength('code', 255) + ->requirePresence('code', 'create') + ->notEmptyString('code'); + + $validator + ->scalar('name') + ->maxLength('name', 255) + ->requirePresence('name', 'create') + ->notEmptyString('name'); + + $validator + ->scalar('url_layer') + ->maxLength('url_layer', 255) + ->requirePresence('url_layer', 'create') + ->notEmptyString('url_layer'); + + $validator + ->integer('clusterize') + ->notEmptyString('clusterize'); + + $validator + ->integer('visible') + ->notEmptyString('visible'); + + $validator + ->scalar('style') + ->maxLength('style', 4294967295) + ->allowEmptyString('style'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MenuItemsTable.php b/idrocap_wa/src/Model/Table/MenuItemsTable.php new file mode 100644 index 0000000..b39dff7 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MenuItemsTable.php @@ -0,0 +1,135 @@ +setTable('menu_items'); + $this->setDisplayField('title'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ParentMenuItems', [ + 'className' => 'MenuItems', + 'foreignKey' => 'menu_item_id', + ]); + $this->belongsTo('MenuSections', [ + 'foreignKey' => 'menu_section_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('ChildMenuItems', [ + 'className' => 'MenuItems', + 'foreignKey' => 'menu_item_id', + ]); + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'menu_item_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'capabilities_menu_items', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('title') + ->maxLength('title', 255) + ->requirePresence('title', 'create') + ->notEmptyString('title'); + + $validator + ->scalar('icon') + ->maxLength('icon', 255) + ->allowEmptyString('icon'); + + $validator + ->scalar('link') + ->maxLength('link', 255) + ->allowEmptyString('link'); + + $validator + ->scalar('confirm') + ->maxLength('confirm', 255) + ->allowEmptyString('confirm'); + + $validator + ->scalar('method') + ->maxLength('method', 255) + ->allowEmptyString('method'); + + $validator + ->integer('menu_item_id') + ->allowEmptyString('menu_item_id'); + + $validator + ->integer('menu_section_id') + ->requirePresence('menu_section_id', 'create') + ->notEmptyString('menu_section_id'); + + $validator + ->integer('menu_order') + ->notEmptyString('menu_order'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('menu_item_id', 'MenuItems'), ['errorField' => 'menu_item_id']); + $rules->add($rules->existsIn('menu_section_id', 'MenuSections'), ['errorField' => 'menu_section_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/MenuSectionsTable.php b/idrocap_wa/src/Model/Table/MenuSectionsTable.php new file mode 100644 index 0000000..8959a24 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MenuSectionsTable.php @@ -0,0 +1,80 @@ +setTable('menu_sections'); + $this->setDisplayField('title'); + $this->setPrimaryKey('id'); + + $this->hasMany('MenuItems', [ + 'foreignKey' => 'menu_section_id', + ]); + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'menu_section_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'capabilities_menu_sections', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('title') + ->maxLength('title', 255) + ->requirePresence('title', 'create') + ->notEmptyString('title'); + + $validator + ->scalar('icon') + ->maxLength('icon', 255) + ->allowEmptyString('icon'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MessageStatusesTable.php b/idrocap_wa/src/Model/Table/MessageStatusesTable.php new file mode 100644 index 0000000..a50b78d --- /dev/null +++ b/idrocap_wa/src/Model/Table/MessageStatusesTable.php @@ -0,0 +1,65 @@ +setTable('message_statuses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('Messages', [ + 'foreignKey' => 'message_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MessageTypesTable.php b/idrocap_wa/src/Model/Table/MessageTypesTable.php new file mode 100644 index 0000000..c33469e --- /dev/null +++ b/idrocap_wa/src/Model/Table/MessageTypesTable.php @@ -0,0 +1,69 @@ +setTable('message_types'); + $this->setDisplayField('label'); + $this->setPrimaryKey('id'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 45) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('label') + ->maxLength('label', 45) + ->allowEmptyString('label'); + + $validator + ->integer('dispatching_bitmask_weight') + ->requirePresence('dispatching_bitmask_weight', 'create') + ->notEmptyString('dispatching_bitmask_weight'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MessagesTable.php b/idrocap_wa/src/Model/Table/MessagesTable.php new file mode 100644 index 0000000..f06dda1 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MessagesTable.php @@ -0,0 +1,150 @@ +setTable('messages'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + ]); + $this->belongsTo('MessageTypes', [ + 'foreignKey' => 'message_type_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + ]); + $this->belongsTo('MessageStatuses', [ + 'foreignKey' => 'message_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Organisations', [ + 'foreignKey' => 'organisation_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('controllable_object_id') + ->allowEmptyString('controllable_object_id'); + + $validator + ->integer('message_type_id') + ->requirePresence('message_type_id', 'create') + ->notEmptyString('message_type_id'); + + $validator + ->scalar('content') + ->allowEmptyString('content'); + + $validator + ->integer('user_id') + ->allowEmptyString('user_id'); + + $validator + ->integer('message_status_id') + ->requirePresence('message_status_id', 'create') + ->notEmptyString('message_status_id'); + + $validator + ->scalar('mgroup') + ->maxLength('mgroup', 255) + ->requirePresence('mgroup', 'create') + ->notEmptyString('mgroup'); + + $validator + ->scalar('event_string') + ->maxLength('event_string', 255) + ->requirePresence('event_string', 'create') + ->notEmptyString('event_string') + ->add('event_string', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->dateTime('last_update') + ->allowEmptyDateTime('last_update'); + + $validator + ->integer('organisation_id') + ->allowEmptyString('organisation_id'); + + $validator + ->scalar('contact') + ->maxLength('contact', 255) + ->allowEmptyString('contact'); + + $validator + ->scalar('not_delivered_reason') + ->maxLength('not_delivered_reason', 255) + ->allowEmptyString('not_delivered_reason'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['event_string']), ['errorField' => 'event_string']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('message_type_id', 'MessageTypes'), ['errorField' => 'message_type_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('message_status_id', 'MessageStatuses'), ['errorField' => 'message_status_id']); + $rules->add($rules->existsIn('organisation_id', 'Organisations'), ['errorField' => 'organisation_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/MobileComponentsTable.php b/idrocap_wa/src/Model/Table/MobileComponentsTable.php new file mode 100644 index 0000000..0e45dee --- /dev/null +++ b/idrocap_wa/src/Model/Table/MobileComponentsTable.php @@ -0,0 +1,77 @@ +setTable('mobile_components'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'mobile_component_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'capabilities_mobile_components', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('menu_item') + ->maxLength('menu_item', 255) + ->requirePresence('menu_item', 'create') + ->notEmptyString('menu_item'); + + $validator + ->boolean('is_enabled') + ->notEmptyString('is_enabled'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php b/idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php new file mode 100644 index 0000000..fe7d4c2 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php @@ -0,0 +1,74 @@ +setTable('mobile_phone_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('MobilePhones', [ + 'foreignKey' => 'mobile_phone_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('deleted') + ->maxLength('deleted', 45) + ->allowEmptyString('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MobilePhonesTable.php b/idrocap_wa/src/Model/Table/MobilePhonesTable.php new file mode 100644 index 0000000..3cf9a20 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MobilePhonesTable.php @@ -0,0 +1,111 @@ +setTable('mobile_phones'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('MobilePhoneDescriptions', [ + 'foreignKey' => 'mobile_phone_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->regex('value', '/^[0-9]*$/i'); + + $validator + ->boolean('is_system') + ->allowEmptyString('is_system'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('mobile_phone_description_id') + ->requirePresence('mobile_phone_description_id', 'create') + ->allowEmptyString('mobile_phone_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('mobile_phone_description_id', 'MobilePhoneDescriptions'), ['errorField' => 'mobile_phone_description_id']); + $rules->add($rules->isUnique(['value'], __('Cellulare già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/NotificationTypesTable.php b/idrocap_wa/src/Model/Table/NotificationTypesTable.php new file mode 100644 index 0000000..0ee11bf --- /dev/null +++ b/idrocap_wa/src/Model/Table/NotificationTypesTable.php @@ -0,0 +1,65 @@ +setTable('notification_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('Notifications', [ + 'foreignKey' => 'notification_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/NotificationsTable.php b/idrocap_wa/src/Model/Table/NotificationsTable.php new file mode 100644 index 0000000..122464a --- /dev/null +++ b/idrocap_wa/src/Model/Table/NotificationsTable.php @@ -0,0 +1,122 @@ +setTable('notifications'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('NotificationTypes', [ + 'foreignKey' => 'notification_type_id', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + $validator + ->dateTime('read_by_user') + ->allowEmptyDateTime('read_by_user'); + + $validator + ->integer('notification_type_id') + ->allowEmptyString('notification_type_id'); + + $validator + ->scalar('info') + ->requirePresence('info', 'create') + ->notEmptyString('info'); + + $validator + ->scalar('thread') + ->maxLength('thread', 45) + ->requirePresence('thread', 'create') + ->notEmptyString('thread'); + + $validator + ->scalar('ngroup') + ->maxLength('ngroup', 255) + ->allowEmptyString('ngroup'); + + $validator + ->integer('controllable_object_id') + ->allowEmptyString('controllable_object_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('notification_type_id', 'NotificationTypes'), ['errorField' => 'notification_type_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/OrganisationTypesTable.php b/idrocap_wa/src/Model/Table/OrganisationTypesTable.php new file mode 100644 index 0000000..17db0d4 --- /dev/null +++ b/idrocap_wa/src/Model/Table/OrganisationTypesTable.php @@ -0,0 +1,69 @@ +setTable('organisation_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Organisations', [ + 'foreignKey' => 'organisation_type_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/OrganisationsTable.php b/idrocap_wa/src/Model/Table/OrganisationsTable.php new file mode 100644 index 0000000..ef98dda --- /dev/null +++ b/idrocap_wa/src/Model/Table/OrganisationsTable.php @@ -0,0 +1,286 @@ +setTable('organisations'); + $this->setDisplayField('actor.description'); + $this->setPrimaryKey('id'); + + $this->belongsTo('OrganisationTypes', [ + 'foreignKey' => 'organisation_type_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('OrganisationActors', [ + 'className' => 'Actors', + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('Users', [ + 'foreignKey' => 'organisation_id', + ]); + $this->addBehavior('Muffin/Trash.Trash'); + + // non invertire l'ordine di aggiunta di questi 2 behaviors perchè le callbacks gestite devono essere eseguite in un certo ordine! + $this->addBehavior('ControllableObjectInterface'); + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('acronym') + ->maxLength('acronym', 45) + ->notEmptyString('acronym') + ->requirePresence('acronym'); + + $validator + ->scalar('geoposition') + ->allowEmptyString('geoposition'); + + $validator + ->scalar('address') + ->maxLength('address', 255) + ->notEmptyString('address') + ->requirePresence('address'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->notEmptyString('district') + ->requirePresence('district'); + + $validator + ->scalar('cap') + ->maxLength('cap', 255) + ->notEmptyString('cap') + ->requirePresence('cap'); + + $validator + ->scalar('province') + ->maxLength('province', 255) + ->notEmptyString('province') + ->requirePresence('province'); + + $validator + ->integer('organisation_type_id') + ->requirePresence('organisation_type_id', 'create') + ->notEmptyString('organisation_type_id'); + + $validator + ->integer('actor_id') + ->notEmptyString('actor_id') + ->add('actor_id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->scalar('pec') + ->email('pec', true) + ->maxLength('pec', 255) + ->allowEmptyString('pec'); + + $validator + ->scalar('coordinates') + ->maxLength('coordinates', 4294967295) + ->notEmptyString('coordinates') + ->requirePresence('coordinates'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->scalar('photo') + ->maxLength('photo', 2555) + ->allowEmptyString('photo'); + + $validator + ->integer('controllable_object_interface_id') + ->allowEmptyString('controllable_object_interface_id'); + + return $validator; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['actor']['actor_type_id'] = 1; + + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare l\'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geoposition'] = $data['feature_collection']; + } + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + $rules->add($rules->existsIn('organisation_type_id', 'OrganisationTypes'), ['errorField' => 'organisation_type_id']); + + $rules->addCreate(function ($entity, $options) { + // controllo se l'organizzazione è di tipo Cittadini + if ($entity->isNew() && $entity->organisation_type_id === 7) { + $organisations = $this->find()->where(['organisation_type_id' => 7])->count(); + if ($organisations >= 1) { + return false; + } + } + return true; + }, 'validateOrganisationType', [ + 'errorField' => 'organisation_type_id', + "message" => __("L'organizzazione non può essere di tipo Cittadini in quanto ne esiste già una.") + ]); + + $rules->addUpdate(function ($entity, $options) { + if ($entity->getOriginal('organisation_type_id') === 7 && $entity->organisation_type_id !== 7) { + return false; + } + return true; + }, 'validateOrganisationType', [ + 'errorField' => 'organisation_type_id', + "message" => __("L'organizzazione è di tipo Cittadini e non è consentito modificarne il tipo.") + ]); + return $rules; + } + + /** + * can_index + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_index(User $user, Array &$options): Bool + { + if (!$user->hasCapability(['configuration.organisations.read', 'voluntary_organisation'])) + { + $options['error']['capabilities'] = ['configuration.organisations.read', 'voluntary_organisation']; + return false; + } + + $options['finder'] = 'all'; + $type = $options['type']; + if($type == "voluntary" || ($user->hasCapability(['voluntary_organisation']) && !$user->hasCapability(['configuration.organisations.read']))) + { + $options['finder'] = 'onlyType567'; + } + return true; + } + + /** + * findOnlyType567 + * + * @param SelectQuery $query + * @param Array $options + * @return SelectQuery + */ + public function findOnlyType567(SelectQuery $query, Array $params): SelectQuery + { + return $query->where(['Organisations.organisation_type_id IN' => [5, 6, 7]]); + } + + /** + * applySearchParams + * + * @param SelectQuery $query + * @param Array $params + * @return SelectQuery + */ + public function applySearchParams(SelectQuery $query, Array $params): SelectQuery + { + $search_params = [ + 'id' => 'Organisations.id', + 'organisation_description' => 'Actors.description', + 'acronym' => 'Organisations.acronym', + 'organisation_type_id' => 'Organisations.organisation_type_id', + 'district' => 'Organisations.district', + 'province' => 'Organisations.province', + ]; + + $searck_keys = array_keys($search_params); + + $search_conditions = collection($params) + ->filter(function ($paramValue, $paramKey) use ($searck_keys) { + return in_array($paramKey, $searck_keys); + }) + ->map(function ($paramValue, $paramKey) use ($search_params) { + return [$search_params[$paramKey] => $paramValue]; + }) + ->reduce(function ($acc, $search_condition) { + $acc[] = $search_condition; + return $acc; + }, []); + + if (!empty($search_conditions)) { + $query->where($search_conditions); + } + return $query; + } +} diff --git a/idrocap_wa/src/Model/Table/PecDescriptionsTable.php b/idrocap_wa/src/Model/Table/PecDescriptionsTable.php new file mode 100644 index 0000000..8f628b6 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PecDescriptionsTable.php @@ -0,0 +1,74 @@ +setTable('pec_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Pecs', [ + 'foreignKey' => 'pec_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/PecsTable.php b/idrocap_wa/src/Model/Table/PecsTable.php new file mode 100644 index 0000000..578021a --- /dev/null +++ b/idrocap_wa/src/Model/Table/PecsTable.php @@ -0,0 +1,111 @@ +setTable('pecs'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('PecDescriptions', [ + 'foreignKey' => 'pec_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->email('value', true); + + $validator + ->boolean('is_system') + ->notEmptyString('is_system'); + + $validator + ->boolean('enable_notifications') + ->notEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('pec_description_id') + ->requirePresence('pec_description_id', 'create') + ->allowEmptyString('pec_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('pec_description_id', 'PecDescriptions'), ['errorField' => 'pec_description_id']); + $rules->add($rules->isUnique(['value'], __('Indirizzo PEC già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/PermissionsTable.php b/idrocap_wa/src/Model/Table/PermissionsTable.php new file mode 100644 index 0000000..2a174b0 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PermissionsTable.php @@ -0,0 +1,85 @@ +setTable('permissions'); + $this->setDisplayField(['capability_id', 'group_id']); + $this->setPrimaryKey(['capability_id', 'group_id']); + + $this->belongsTo('Capabilities', [ + 'foreignKey' => 'capability_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Groups', [ + 'foreignKey' => 'group_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_id', 'Capabilities'), ['errorField' => 'capability_id']); + $rules->add($rules->existsIn('group_id', 'Groups'), ['errorField' => 'group_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php b/idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php new file mode 100644 index 0000000..412021b --- /dev/null +++ b/idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php @@ -0,0 +1,73 @@ +setTable('phone_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Phones', [ + 'foreignKey' => 'phone_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/PhonesTable.php b/idrocap_wa/src/Model/Table/PhonesTable.php new file mode 100644 index 0000000..6736469 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PhonesTable.php @@ -0,0 +1,103 @@ +setTable('phones'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('PhoneDescriptions', [ + 'foreignKey' => 'phone_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->regex('value', '/^[0-9]*$/i'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('phone_description_id') + ->requirePresence('phone_description_id', 'create') + ->allowEmptyString('phone_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('phone_description_id', 'PhoneDescriptions'), ['errorField' => 'phone_description_id']); + $rules->add($rules->isUnique(['value'], __('Telefono già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/PrivacyTable.php b/idrocap_wa/src/Model/Table/PrivacyTable.php new file mode 100644 index 0000000..1bc5120 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PrivacyTable.php @@ -0,0 +1,90 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\Privacy get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\Privacy findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\Privacy patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\Privacy> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\Privacy|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\Privacy saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy> deleteManyOrFail(iterable $entities, array $options = []) + * + * @mixin \Cake\ORM\Behavior\TimestampBehavior + */ +class PrivacyTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('privacy'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->hasMany('PrivacyUsers', [ + 'foreignKey' => 'privacy_id', + ]); + + $this->belongsToMany('Users', [ + 'foreignKey' => 'privacy_id', + 'targetForeignKey' => 'user_id', + 'joinTable' => 'privacy_users', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 4294967295) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } + + /** + * @return Privacy + */ + public function findPrivacy(): Privacy + { + $latestPrivacy = $this->find() + ->orderBy(['created' => 'DESC']) + ->first(); + + return $latestPrivacy ?? $this->newEmptyEntity(); + } +} diff --git a/idrocap_wa/src/Model/Table/PrivacyUsersTable.php b/idrocap_wa/src/Model/Table/PrivacyUsersTable.php new file mode 100644 index 0000000..3f6f5bb --- /dev/null +++ b/idrocap_wa/src/Model/Table/PrivacyUsersTable.php @@ -0,0 +1,123 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\PrivacyUser get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\PrivacyUser findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\PrivacyUser patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\PrivacyUser> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\PrivacyUser|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\PrivacyUser saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser> deleteManyOrFail(iterable $entities, array $options = []) + * + * @mixin \Cake\ORM\Behavior\TimestampBehavior + */ +class PrivacyUsersTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('privacy_users'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Privacy', [ + 'foreignKey' => 'privacy_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('privacy_id') + ->notEmptyString('privacy_id'); + + $validator + ->integer('user_id') + ->notEmptyString('user_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn(['privacy_id'], 'Privacy'), ['errorField' => 'privacy_id']); + $rules->add($rules->existsIn(['user_id'], 'Users'), ['errorField' => 'user_id']); + + return $rules; + } + + public function saveConsent(int $userId, int $privacyId): bool + { + $acceptPrivacy = $this->newEmptyEntity(); + $acceptedPrivacy = $this->patchEntity($acceptPrivacy, [ + 'user_id' => $userId, + 'privacy_id' => $privacyId + ]); + + if ($this->save($acceptedPrivacy)) { + return true; + } + + return false; + } + + public function hasConsent(int $userId): bool + { + $userConsent = $this->find() + ->where(['user_id' => $userId]) + ->first(); + + if (isset($userConsent)) { + return true; + } + + return false; + } +} diff --git a/idrocap_wa/src/Model/Table/PushNotificationsTable.php b/idrocap_wa/src/Model/Table/PushNotificationsTable.php new file mode 100644 index 0000000..6c083dd --- /dev/null +++ b/idrocap_wa/src/Model/Table/PushNotificationsTable.php @@ -0,0 +1,101 @@ +setTable('push_notifications'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->allowEmptyString('value'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->allowEmptyString('delivery_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->addCreate(function ($entity, $options) { + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return false; + return $this->find()->matching('Deliveries')->where(['PushNotifications.value' => $entity->value, 'Deliveries.actor_id' => $user->actor_id])->first() === null; + }, 'value', [ + 'errorField' => 'value', + 'message' => __('Non puoi associare nuovamente questo token allo stesso utente') + ]); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/SnapshotsTable.php b/idrocap_wa/src/Model/Table/SnapshotsTable.php new file mode 100644 index 0000000..b77a390 --- /dev/null +++ b/idrocap_wa/src/Model/Table/SnapshotsTable.php @@ -0,0 +1,118 @@ +setTable('snapshots'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjectTypes', [ + 'foreignKey' => 'controllable_object_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('controllable_object_type_id') + ->allowEmptyString('controllable_object_type_id'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->scalar('object_snapshot') + ->maxLength('object_snapshot', 4294967295) + ->requirePresence('object_snapshot', 'create') + ->notEmptyString('object_snapshot'); + + $validator + ->dateTime('date') + ->requirePresence('date', 'create') + ->notEmptyDateTime('date'); + + $validator + ->integer('user_id') + ->allowEmptyString('user_id'); + + $validator + ->scalar('controller_action') + ->requirePresence('controller_action', 'create') + ->notEmptyString('controller_action'); + + $validator + ->integer('unpacked_with_version') + ->allowEmptyString('unpacked_with_version'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('controllable_object_type_id', 'ControllableObjectTypes'), ['errorField' => 'controllable_object_type_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/TagsTable.php b/idrocap_wa/src/Model/Table/TagsTable.php new file mode 100644 index 0000000..1c6e1a3 --- /dev/null +++ b/idrocap_wa/src/Model/Table/TagsTable.php @@ -0,0 +1,94 @@ +setTable('tags'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsToMany('Attachments', [ + 'foreignKey' => 'tag_id', + 'targetForeignKey' => 'attachment_id', + 'joinTable' => 'attachments_tags', + ]); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'LEFT', + ]); + + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('code') + ->maxLength('code', 255) + ->allowEmptyString('code'); + + $validator + ->scalar('class') + ->maxLength('class', 255) + ->allowEmptyString('class'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + return $validator; + } + + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 12; + } +} diff --git a/idrocap_wa/src/Model/Table/TelegramChatsTable.php b/idrocap_wa/src/Model/Table/TelegramChatsTable.php new file mode 100644 index 0000000..f6e5d36 --- /dev/null +++ b/idrocap_wa/src/Model/Table/TelegramChatsTable.php @@ -0,0 +1,99 @@ +setTable('telegram_chats'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->allowEmptyString('value'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->allowEmptyString('delivery_id'); + + $validator + ->integer('telegram_chat_description_id') + ->allowEmptyString('telegram_chat_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->isUnique(['value'], __('ID Chat Telegram già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/TelegramContactsTable.php b/idrocap_wa/src/Model/Table/TelegramContactsTable.php new file mode 100644 index 0000000..4827105 --- /dev/null +++ b/idrocap_wa/src/Model/Table/TelegramContactsTable.php @@ -0,0 +1,116 @@ +setTable('telegram_contacts'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('phone_number') + ->maxLength('phone_number', 255) + ->requirePresence('phone_number', 'create') + ->notEmptyString('phone_number'); + + $validator + ->scalar('telegram_user_id') + ->maxLength('telegram_user_id', 255) + ->allowEmptyString('telegram_user_id'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->requirePresence('delivery_id', 'create') + ->notEmptyString('delivery_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->integer('telegram_contact_status_id') + ->requirePresence('telegram_contact_status_id', 'create') + ->notEmptyString('telegram_contact_status_id'); + + $validator + ->scalar('error_message') + ->maxLength('error_message', 255) + ->allowEmptyString('error_message'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php b/idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php new file mode 100644 index 0000000..0f35afd --- /dev/null +++ b/idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php @@ -0,0 +1,137 @@ +setTable('unpacked_water_drawing_paperwork_snapshots'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Snapshots', [ + 'foreignKey' => 'snapshot_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('snapshot_id') + ->notEmptyString('snapshot_id'); + + $validator + ->integer('unpacking_version') + ->requirePresence('unpacking_version', 'create') + ->notEmptyString('unpacking_version'); + + $validator + ->scalar('who') + ->maxLength('who', 255) + ->allowEmptyString('who'); + + $validator + ->dateTime('when') + ->allowEmptyDateTime('when'); + + $validator + ->scalar('what') + ->maxLength('what', 255) + ->allowEmptyString('what'); + + $validator + ->scalar('creator') + ->maxLength('creator', 255) + ->allowEmptyString('creator'); + + $validator + ->scalar('modifier') + ->maxLength('modifier', 255) + ->allowEmptyString('modifier'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->scalar('water_drawing_paperwork_status') + ->maxLength('water_drawing_paperwork_status', 255) + ->allowEmptyString('water_drawing_paperwork_status'); + + $validator + ->scalar('gc_user') + ->maxLength('gc_user', 255) + ->allowEmptyString('gc_user'); + + $validator + ->scalar('drar_user') + ->maxLength('drar_user', 255) + ->allowEmptyString('drar_user'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('snapshot_id', 'Snapshots'), ['errorField' => 'snapshot_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/UsersTable.php b/idrocap_wa/src/Model/Table/UsersTable.php new file mode 100644 index 0000000..509e662 --- /dev/null +++ b/idrocap_wa/src/Model/Table/UsersTable.php @@ -0,0 +1,476 @@ +setTable('users'); + $this->setDisplayField('actor.description'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Organisations', [ + 'foreignKey' => 'organisation_id', + ]); + $this->belongsTo('Languages', [ + 'foreignKey' => 'language_id', + ]); + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('UserActors', [ + 'className' => 'Actors', + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('PrivacyUsers', [ + 'foreignKey' => 'user_id', + ]); + $this->hasMany('Memberships', [ + 'foreignKey' => 'user_id', + ]); + $this->belongsToMany('Groups', [ + 'foreignKey' => 'user_id', + 'targetForeignKey' => 'group_id', + 'joinTable' => 'memberships', + ]); + $this->hasMany('WaterDrawingPaperworkHistories', [ + 'foreignKey' => 'user_id', + ]); + $this->hasMany('WaterDrawingAntimafiaCertificationRequests', [ + 'foreignKey' => 'user_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('organisation_id') + ->requirePresence('organisation_id', true) + ->notEmptyString('organisation_id'); + + $validator + ->scalar('username') + ->maxLength('username', 255) + ->requirePresence('username', 'create') + ->notEmptyString('username'); + + $validator + ->scalar('password') + ->maxLength('password', 255) + ->requirePresence('password', 'create') + ->notEmptyString('password') + ->minLength('password', Configure::read('App.minPasswordLength'), __('La password deve contenere almeno {0} caratteri', Configure::read('App.minPasswordLength'))) + ->add('password', 'min_capital_letters', [ + 'rule' => function ($value){ + return strlen(preg_replace('![^A-Z]+!', '', $value)) >= Configure::read('App.minPasswordCapitalCharacters'); + }, + 'message' => __('La password deve contenere almeno {0} carattere/i maiuscolo/i', Configure::read('App.minPasswordCapitalCharacters')) + ]) + ->add('password', 'min_numbers', [ + 'rule' => function ($value) { + return strlen(preg_replace('![^0-9]+!', '', $value)) >= Configure::read('App.minPasswordNumberCharacters'); + }, + 'message' => __('La password deve contenere almeno {0} numero/i', Configure::read('App.minPasswordNumberCharacters')) + ]) + ->add('password', 'min_special_characters', [ + 'rule' => function ($value, $context) { + $chars = str_split(Configure::read('App.passwordSpecialCharacters')); + $count = 0; + + foreach($chars as $char) + { + $count+=substr_count($value, $char); + } + + return $count >= Configure::read('App.minPasswordSpecialCharacters'); + }, + 'message' => __('La password deve contenere almeno {1} carattere/i speciale/i tra "{0}"', Configure::read('App.passwordSpecialCharacters'), Configure::read('App.minPasswordSpecialCharacters')) + ]); + + $validator + ->scalar('surname') + ->maxLength('surname', 255) + ->requirePresence('surname', 'create') + ->notEmptyString('surname'); + + $validator + ->scalar('name') + ->maxLength('name', 255) + ->requirePresence('name', 'create') + ->notEmptyString('name'); + + $validator + ->scalar('address') + ->maxLength('address', 255) + ->allowEmptyString('address'); + + $validator + ->scalar('city') + ->maxLength('city', 255) + ->allowEmptyString('city'); + + $validator + ->scalar('cap') + ->maxLength('cap', 255) + ->allowEmptyString('cap'); + + $validator + ->scalar('tax_code') + ->maxLength('tax_code', 255) + ->allowEmptyString('tax_code') + ->regex('tax_code', '/^[A-Z]{6}[0-9LMNPQRSTUV]{2}[A-EHLMPR-T]{1}[0-9LMNPQRSTUV]{2}[A-Z]{1}[0-9LMNPQRSTUV]{3}[A-Z]{1}$/', 'Il formato del codice fiscale è errato.'); + + $validator + ->scalar('photo') + ->maxLength('photo', 255) + ->allowEmptyString('photo'); + + $validator + ->scalar('birthplace') + ->maxLength('birthplace', 255) + ->allowEmptyString('birthplace'); + + $validator + ->dateTime('birthday') + ->allowEmptyDateTime('birthday'); + + $validator + ->scalar('gender') + ->maxLength('gender', 1) + ->allowEmptyString('gender'); + + $validator + ->integer('language_id') + ->allowEmptyString('language_id'); + + $validator + ->scalar('password_recovery_token') + ->maxLength('password_recovery_token', 255) + ->allowEmptyString('password_recovery_token'); + + $validator + ->integer('password_recovery_counter') + ->allowEmptyString('password_recovery_counter'); + + $validator + ->integer('actor_id') + ->notEmptyString('actor_id') + ->add('actor_id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + if (!empty($data['birthday'])) { + $data['birthday'] = $data['birthday'] . ' 12:00:00'; + } + $isDefaultCitizen = $options['skipCitizenOrg'] ?? false; + $data['actor']['actor_type_id'] = 5; + if (isset($data['name']) && isset($data['surname'])) { + $data['actor']['description'] = $data['name'] . ' ' . $data['surname']; + } + if (!empty($data['organisation_id']) && !$isDefaultCitizen) { + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) $data['organisation_id'] = null; + if ($user && !$user->hasCapability('configuration.users.add')) $data['organisation_id'] = $user->organisation_id; + } + + if (isset($data['groups']['_ids']) && !empty($data['groups']['_ids']) && is_array($data['groups']['_ids'])) { + $user = Router::getRequest()->getAttribute('identity'); + if ($user && !$user->sys_admin && !$user->hasCapability(['configuration.users.profiles'])) { + $associable_user_groups_ids = array_keys($this->getAssociableUserGroups(as_list: true)->toArray()); + $data['groups']['_ids'] = array_values(array_intersect($data['groups']['_ids'], $associable_user_groups_ids)); + } + } + + if (isset($data['tax_code'])) { + $data['tax_code'] = strtoupper($data['tax_code']); + } + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['username']), ['errorField' => 'username']); + $rules->add($rules->isUnique(['email']), ['errorField' => 'email']); + $rules->add($rules->isUnique(['tax_code']), ['errorField' => 'tax_code']); + $rules->add($rules->existsIn('organisation_id', 'Organisations'), ['errorField' => 'organisation_id']); + $rules->add($rules->existsIn('language_id', 'Languages'), ['errorField' => 'language_id']); + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + $rules->add(function ($entity, $options) { + $attachment = $entity['user_photo'] ?? null; + if ($attachment) $attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($attachment); + if (empty($attachment['tmp_name']) || !isset($attachment['error']) || $attachment['error'] !== 0) return true; + $attributes = getimagesize($attachment['tmp_name']); + $width = (String)($attributes['0'] ?? 0); + $height = (String)($attributes['1'] ?? 0); + if ($width !== '160' || $height !== '160') return false; + $file_name = (String)($entity->id ?? 0) . '_' . time() . '.jpg'; + try + { + $res = \App\WGS\FileStorage\FileStorageFactory::create()->saveFile(Configure::read('App.userPhotoPath') . "/" . $file_name, $attachment['tmp_name']); + $entity->photo = $file_name; + return true; + } + catch(\Exception $we) + { + return false; + } + }, 'user_photo_check', [ + 'errorField' => 'user_photo', + 'message' => __('Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)'), + ]); + return $rules; + } + + /** + * can_index + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_index(User $user, Array &$options): Bool + { + if (!$user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) { + $options['error']['capabilities'] = ['configuration.users.read', 'configuration.users.read_foo']; + return false; + } + $options['finder'] = 'all'; + if (!$user->hasCapability(['configuration.users.read'])) { + $options['finder'] = 'foo'; + $options['user'] = $user; + } + return true; + } + + /** + * findFoo + * + * @param SelectQuery $query + * @param Array $options + * @return SelectQuery + */ + public function findFoo(SelectQuery $query, Array $params): SelectQuery + { + return $query->where(['Users.organisation_id is not null', 'Users.organisation_id' => $params['user']->organisation_id]); + } + + /** + * applySearchParams + * + * @param SelectQuery $query + * @param Array $params + * @return SelectQuery + */ + public function applySearchParams(SelectQuery $query, Array $params): SelectQuery + { + $search_params = [ + 'id' => 'Users.id', + 'name' => 'Users.name', + 'surname' => 'Users.surname', + 'organisation_description' => 'Actors.description', + ]; + + $searck_keys = array_keys($search_params); + + $search_conditions = collection($params) + ->filter(function ($paramValue, $paramKey) use ($searck_keys) { + return in_array($paramKey, $searck_keys); + }) + ->map(function ($paramValue, $paramKey) use ($search_params) { + return [$search_params[$paramKey] => $paramValue]; + }) + ->reduce(function ($acc, $search_condition) { + $acc[] = $search_condition; + return $acc; + }, []); + + if (!empty($search_conditions)) { + $query->where($search_conditions); + } + return $query; + } + + /** + * getAssociableUserGroups + * + * returns the groups that the user can associate to himself or to others + * + * @param Bool $as_list + * @return SelectQuery + */ + public function getAssociableUserGroups(Bool $as_list = false): SelectQuery + { + $finder = $as_list ? 'list' : 'all'; + $groups = TableRegistry::getTableLocator()->get('Groups')->find($finder)->contain(['Actors']); + + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return $groups->where(['Groups.id < 0']); + + // se posso associare agli utenti qualunque profilo, restituisco la lista completa dei profili: + if ($user->sys_admin || $user->hasCapability(['configuration.users.profiles'])) return $groups; + + $associable_user_groups_ids = TableRegistry::getTableLocator()->get('Groups')->find() + ->contain(['Actors']) + ->select(['id']) + ->matching('ParentGroups.Users') + ->where(['Users.id' => $user->id]); + + return $groups->where(['Groups.id IN' => $associable_user_groups_ids]); + } + + + /** + * @param array $data + * @return User|false + */ + public function createCitizen(User $user, array $data): User|false + { + $this->getConnection()->begin(); + try { + $default_profile = $this->Groups->find() + ->contain(['Actors']) + // prendiamo il profilo con group_code 1 (valore univoco per il profilo cittadini) + ->where(['Groups.group_code' => 'citizen_group']) + ->first(); + $user['groups'] = [$default_profile]; + // Prendo l'organizzazione di default per i cittadini + $defaultCitizenOrg = $this->Organisations->find()->where(['organisation_type_id' => 7])->first(); + if (!isset($defaultCitizenOrg)) { + throw new InvalidArgumentException('Organizzazione di default per cittadini non trovata'); + } + + $data['is_verified'] = 0; + $data['is_citizen'] = 1; + $data['organisation_id'] = $defaultCitizenOrg->id; + $password = $data['password']; + $confirmPassword = $data['confirmPassword']; + + // inserisco controllo su password e confirmPassword; + if ($password !== $confirmPassword) { + $user->setError('password', __('Le password non corrispondono')); + $user->setError('confirmPassword', __('Le password non corrispondono')); + throw new InvalidArgumentException('Le password non corrispondono'); + } + + $user = $this->patchEntity($user, $data, ['skipCitizenOrg' => true]); + // genro un random_bytes in formato stringa da 32char cosi da garantirne l'univocità. + $user->email_verification_code = bin2hex(random_bytes(16)); + + if (!$this->save($user)) { + throw new RuntimeException('Errore durante il salvataggio di User: ' . json_encode($user->getErrors())); + } + + $emailData = [ + 'value' => $data['email'], + 'email_description_id' => '2', + 'enable_notifications' => '1', + 'delivery' => [ + 'actor_id' => $user->actor_id, + 'delivery_type_id' => 3, + ] + ]; + $email = $this->Actors->Deliveries->Emails->newEntity($emailData); + if (!$this->Actors->Deliveries->Emails->save($email)) { + if ($email->hasErrors() && isset($email->getErrors()['value']['_isUnique'])) { + $user->setError('email', __('Questo indirizzo email è già in uso.')); + } + throw new RuntimeException('Errore durante il salvataggio di Emails: ' . json_encode($email->getErrors())); + } + $this->getConnection()->commit(); + return $user; + } catch (InvalidArgumentException $e) { + $this->getConnection()->rollback(); + Log::error("Argument error: " . $e->getMessage()); + return false; + } catch (RuntimeException $e) { + $this->getConnection()->rollback(); + Log::error("Runtime error: " . $e->getMessage()); + return false; + } + } + + /** + * @param string $emailVerificationCode + * @return User|bool + */ + public function verifyCitizen(string $emailVerificationCode): User|bool + { + $user = $this->find(contain: ['Actors'])->where(['email_verification_code' => $emailVerificationCode, 'is_verified' => 0])->first(); + if (!$user) { + return false; + } + $user = $this->patchEntity($user, ['is_verified' => 1, 'email_verification_code' => null], ['validate' => false, 'skipCitizenOrg' => true]); + return $this->save($user); + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php new file mode 100644 index 0000000..48f7c41 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_antimafia_certification_request_statuses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingAntimafiaCertificationRequests', [ + 'foreignKey' => 'water_drawing_antimafia_certification_request_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php new file mode 100644 index 0000000..fb5900d --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php @@ -0,0 +1,107 @@ +setTable('water_drawing_antimafia_certification_requests'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingAntimafiaCertificationRequestStatuses', [ + 'foreignKey' => 'water_drawing_antimafia_certification_request_status_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_paperwork_id') + ->requirePresence('water_drawing_paperwork_id', 'create') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + $validator + ->integer('water_drawing_antimafia_certification_request_status_id') + ->requirePresence('water_drawing_antimafia_certification_request_status_id', 'create') + ->notEmptyString('water_drawing_antimafia_certification_request_status_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('water_drawing_antimafia_certification_request_status_id', 'WaterDrawingAntimafiaCertificationRequestStatuses'), ['errorField' => 'water_drawing_antimafia_certification_request_status_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php new file mode 100644 index 0000000..e14b579 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php @@ -0,0 +1,76 @@ +setTable('water_drawing_articles'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_articles_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('long_description') + ->maxLength('long_description', 255) + ->allowEmptyString('long_description'); + + $validator + ->boolean('disable') + ->allowEmptyString('disable'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php new file mode 100644 index 0000000..fa5d615 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php @@ -0,0 +1,66 @@ +setTable('water_drawing_derivation_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingDerivations', [ + 'foreignKey' => 'water_drawing_derivation_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('description') + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php new file mode 100644 index 0000000..c153d3f --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php @@ -0,0 +1,206 @@ +setTable('water_drawing_derivations'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingDerivationTypes', [ + 'foreignKey' => 'water_drawing_derivation_type_id', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('water_body') + ->maxLength('water_body', 255) + ->allowEmptyString('water_body'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->allowEmptyString('district'); + + $validator + ->scalar('cadastral_code') + ->maxLength('cadastral_code', 255) + ->allowEmptyString('cadastral_code'); + + $validator + ->scalar('location') + ->maxLength('location', 255) + ->allowEmptyString('location'); + + $validator + ->integer('cadastral_sheet') + ->allowEmptyString('cadastral_sheet'); + + $validator + ->integer('cadastral_parcel') + ->allowEmptyString('cadastral_parcel'); + + $validator + ->scalar('latitude') + ->maxLength('latitude', 255) + ->allowEmptyString('latitude'); + + $validator + ->scalar('longitude') + ->maxLength('longitude', 255) + ->allowEmptyString('longitude'); + + $validator + ->scalar('istat') + ->maxLength('istat', 255) + ->allowEmptyString('istat'); + + $validator + ->scalar('derivation_status') + ->maxLength('derivation_status', 255) + ->allowEmptyString('derivation_status'); + + $validator + ->integer('withdrawals_amount') + ->allowEmptyString('withdrawals_amount'); + + $validator + ->numeric('annual_volume') + ->allowEmptyString('annual_volume'); + + $validator + ->numeric('average_flow_rate') + ->allowEmptyString('average_flow_rate'); + + $validator + ->integer('water_drawing_derivation_use_id') + ->allowEmptyString('water_drawing_derivation_use_id'); + + $validator + ->integer('water_drawing_derivation_type_id') + ->allowEmptyString('water_drawing_derivation_type_id'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_derivation_type_id', 'WaterDrawingDerivationTypes'), ['errorField' => 'water_drawing_derivation_type_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add(function ($entity, $options){ + if(isset($entity->cadastral_code, $entity->cadastral_sheet, $entity->cadastral_parcel) && !(empty($entity->latitude) && empty($entity->longitude))){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + if(isset($coordinates)){ + return GeoValidation::checkCadastralCoordinates($entity->latitude, $entity->longitude, strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + } + } + return true; + }, ['errorField' => 'latitude', 'message' => __('Le coordinate non ricadono all\'interno della particella selezionata.')]); + $rules->add(function ($entity, $options){ + if(isset($entity->cadastral_code, $entity->cadastral_sheet, $entity->cadastral_parcel) && !(empty($entity->latitude) && empty($entity->longitude))){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + if(isset($coordinates)){ + return GeoValidation::checkCadastralCoordinates($entity->latitude, $entity->longitude, strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + } + } + return true; + }, ['errorField' => 'longitude', 'message' => __('Le coordinate non ricadono all\'interno della particella selezionata.')]); + + return $rules; + } + + public function beforeSave(EventInterface $event, EntityInterface $entity, \ArrayObject $options){ + if(isset($entity->cadastral_code, $entity->cadastral_sheet, $entity->cadastral_parcel) && (empty($entity->latitude) && empty($entity->longitude))){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + if(isset($coordinates)){ + $entity->latitude = $coordinates->latitude; + $entity->longitude = $coordinates->longitude; + $entity->feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":['. $coordinates->longitude .','. $coordinates->latitude .']},"properties":null}]}'; + } + } + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare il punto di prelievo/derivazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geom'] = $data['feature_collection']; + } + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php new file mode 100644 index 0000000..bf7fa0a --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php @@ -0,0 +1,124 @@ +setTable('water_drawing_fees'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('WaterDrawingPayments', [ + 'foreignKey' => 'water_drawing_fee_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->numeric('amount') + ->allowEmptyString('amount'); + + $validator + ->integer('year') + ->requirePresence('year', 'create') + ->notEmptyString('year'); + + $validator + ->integer('water_drawing_paperwork_id') + ->requirePresence('water_drawing_paperwork_id', 'create') + ->notEmptyString('water_drawing_paperwork_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->isUnique(['year', 'water_drawing_paperwork_id'], 'WaterDrawingPaperworks'), ['errorField' => 'year', 'message' => 'Il canone per l\'anno scelto è già impostato.']); + $rules->add(function($entity, $options) { + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find()->where(["id" => $entity->water_drawing_paperwork_id])->first(); + $releaseDate = $waterDrawingPaperworks?->release_date?->year; + $expirationDate = $waterDrawingPaperworks?->expiration_date?->year; + + // se non ho entrambe le date skippo i controlli. + if(!isset($releaseDate) && !isset($expirationDate)){ + return true; + } + + // se ho solo la data di scadenza ma non ho la data di rilascio controllo solo la data di scadenza rispetto al canone. + if(!isset($releaseDate) && isset($expirationDate)) { + return $entity->year <= $expirationDate; + } + + // se ho solo la data di rilascio ma non ho la data di scadenza, controllo solo la data di rilascio rispetto al canone. + if(isset($releaseDate) && !isset($expirationDate)) { + return $entity->year >= $releaseDate; + } + + // in questo caso sono sicuro che ho sia la data di rilascio che di scadenza + // in questo caso specifico controllo che le date siano comprese tra la data di rilascio e la data di scadenza. + return ($entity->year >= $releaseDate) && ($entity->year <= $expirationDate); + }, "yearValidation", ['errorField' => 'year', 'message' => 'Il canone annuale deve essere compreso tra la data di rilascio del provvedimento e la data di scadenza del provvedimento.']); + + return $rules; + } + + public function beforeFind($event, $query, $options, $primary){ + $query->order(['WaterDrawingFees.year' => 'DESC']); + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php new file mode 100644 index 0000000..f024129 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_intended_use_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_intended_use_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php new file mode 100644 index 0000000..d78d20e --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php @@ -0,0 +1,147 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\WaterDrawingIntendedUse findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\WaterDrawingIntendedUse> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse> deleteManyOrFail(iterable $entities, array $options = []) + */ +class WaterDrawingIntendedUsesTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('water_drawing_intended_uses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingIntendedUseTypes', [ + 'foreignKey' => 'water_drawing_intended_use_type_id', + ]); + $this->belongsTo('WaterDrawingWateringSystems', [ + 'foreignKey' => 'water_drawing_watering_system_id', + ]); + $this->belongsToMany('CadastralCropTypes', [ + 'foreignKey' => 'water_drawing_intended_use_id', + 'targetForeignKey' => 'cadastral_crop_type_id', + 'joinTable' => 'cadastral_crop_types_water_drawing_intended_uses', + ]); + $this->hasMany('WaterDrawingMeters', [ + 'foreignKey' => 'water_drawing_intended_use_id', + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('area') + ->maxLength('area', 255) + ->allowEmptyString('area'); + + $validator + ->scalar('cadastral_code') + ->maxLength('cadastral_code', 255) + ->allowEmptyString('cadastral_code'); + + $validator + ->scalar('cadastral_sheet') + ->maxLength('cadastral_sheet', 255) + ->allowEmptyString('cadastral_sheet'); + + $validator + ->scalar('cadastral_parcel') + ->maxLength('cadastral_parcel', 255) + ->allowEmptyString('cadastral_parcel'); + + $validator + ->scalar('consortium_area') + ->maxLength('consortium_area', 255) + ->allowEmptyString('consortium_area'); + + $validator + ->scalar('rated_power_produced') + ->maxLength('rated_power_produced', 255) + ->allowEmptyString('rated_power_produced'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->integer('water_drawing_intended_use_type_id') + ->allowEmptyString('water_drawing_intended_use_type_id'); + + $validator + ->integer('vegetation_match_status') + ->notEmptyString('vegetation_match_status'); + + $validator + ->integer('water_drawing_watering_system_id') + ->allowEmptyString('water_drawing_watering_system_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn(['water_drawing_paperwork_id'], 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn(['water_drawing_intended_use_type_id'], 'WaterDrawingIntendedUseTypes'), ['errorField' => 'water_drawing_intended_use_type_id']); + $rules->add($rules->existsIn(['water_drawing_watering_system_id'], 'WaterDrawingWateringSystems'), ['errorField' => 'water_drawing_watering_system_id']); + + return $rules; + } + + public function beforeSave(EventInterface $event, EntityInterface $entity, \ArrayObject $options) + { + if (empty($options["skipResetIsMismatch"]) || !$options["skipResetIsMismatch"]) $entity->vegetation_match_status = 0; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php new file mode 100644 index 0000000..5eb5b1a --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php @@ -0,0 +1,108 @@ +setTable('water_drawing_measurements'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingMeters', [ + 'foreignKey' => 'water_drawing_meter_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->numeric('volume') + ->requirePresence('volume', 'create') + ->notEmptyString('volume'); + + $validator + ->date('date') + ->requirePresence('date', 'create') + ->notEmptyDate('date'); + + $validator + ->integer('water_drawing_meter_id') + ->requirePresence('water_drawing_meter_id', 'create') + ->notEmptyString('water_drawing_meter_id'); + + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_meter_id', 'WaterDrawingMeters'), ['errorField' => 'water_drawing_meter_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + + $rules->add(function($entity, $option) { + $waterDrawingMeeter = $this->WaterDrawingMeters->find()->where(['id' => $entity->water_drawing_meter_id])->first(); + // controlliamo che la data di misurazione sia successiva o uguale alla data di installazione dello strumento di misurazione + return $entity->date->greaterThanOrEquals($waterDrawingMeeter?->installation_date); + }, "checkMeasurementDate", ["errorField" => "date", "message" => "La data di misurazione non può essere antecedente all'installazione dello strumento di misurazione."]); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php b/idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php new file mode 100644 index 0000000..d6a2252 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php @@ -0,0 +1,118 @@ +setTable('water_drawing_meters'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingToolTypes', [ + 'foreignKey' => 'water_drawing_tool_type_id', + 'joinType' => 'INNER', + ]); + + $this->belongsTo('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_intended_use_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('WaterDrawingMeasurements', [ + 'foreignKey' => 'water_drawing_meter_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_tool_type_id') + ->requirePresence('water_drawing_tool_type_id', 'create') + ->notEmptyString('water_drawing_tool_type_id'); + + $validator + ->integer('water_drawing_intended_use_id') + ->requirePresence('water_drawing_intended_use_id', 'create') + ->notEmptyString('water_drawing_intended_use_id'); + + $validator + ->scalar('manufacturer') + ->maxLength('manufacturer', 255) + ->requirePresence('manufacturer', 'create') + ->allowEmptyString('manufacturer'); + + $validator + ->scalar('part_number') + ->maxLength('part_number', 255) + ->requirePresence('part_number', 'create') + ->notEmptyString('part_number'); + + $validator + ->date('installation_date') + ->requirePresence('installation_date', 'create') + ->allowEmptyDate('installation_date'); + + $validator + ->date('removal_date') + ->allowEmptyDate('removal_date', null, 'update'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_tool_type_id', 'WaterDrawingToolTypes'), ['errorField' => 'water_drawing_tool_type_id']); + $rules->add($rules->existsIn('water_drawing_intended_use_id', 'WaterDrawingIntendedUses'), ['errorField' => 'water_drawing_intended_use_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php new file mode 100644 index 0000000..511977a --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php @@ -0,0 +1,170 @@ +setTable('water_drawing_paperwork_histories'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworkStatuses', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->boolean('result') + ->requirePresence('result', 'create') + ->notEmptyString('result'); + + $validator + ->scalar('note') + ->maxLength('note', 255) + ->allowEmptyString('note'); + + $validator + ->integer('user_id') + ->notEmptyString('user_id'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->integer('water_drawing_paperwork_status_id') + ->requirePresence('water_drawing_paperwork_status_id', 'create') + ->notEmptyString('water_drawing_paperwork_status_id'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_status_id', 'WaterDrawingPaperworkStatuses'), ['errorField' => 'water_drawing_paperwork_status_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add(function ($entity){ + if($entity->result == 0) return ($entity->note != ""); + return true; + }, ['errorField' => 'note', 'message' => ' In caso di rifiuto bisogna inserire una nota.']); + return $rules; + } + + + public function beforeSave(EventInterface $event, WaterDrawingPaperworkHistory $entity, ArrayObject $options){ + $user = Router::getRequest()->getAttribute('identity'); + $entity->user_id = $user->id; + } + + public function afterSave(EventInterface $event, WaterDrawingPaperworkHistory $entity, ArrayObject $options){ + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->where(['WaterDrawingPaperworks.id' => $entity->water_drawing_paperwork_id])->first(); + if($waterDrawingPaperwork->scanned){ + if($entity->result == 1){ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $entity->water_drawing_paperwork_status_id == 3 ? 4 : 6; + }else{ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $entity->water_drawing_paperwork_status_id == 3 ? 2 : 4; + } + }else{ + if($entity->result == 1){ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $waterDrawingPaperwork->water_drawing_paperwork_status_id == 10 ? -1 : -4; + }else{ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $waterDrawingPaperwork->water_drawing_paperwork_status_id == 10 ? 11 : -1; + } + } + if(! $this->WaterDrawingPaperworks->save($waterDrawingPaperwork)){ + \Cake\Log\Log::write('debug', 'Errore durante il salvataggio della pratica. ' . json_encode($waterDrawingPaperwork->getErrors())); + } + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 10; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php new file mode 100644 index 0000000..34eb10b --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php @@ -0,0 +1,136 @@ +setTable('water_drawing_paperwork_pecs'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->integer('user_id') + ->notEmptyString('user_id'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->scalar('document') + ->maxLength('document', 255) + ->requirePresence('document', 'create') + ->notEmptyString('document'); + + $validator + ->scalar('protocol_number') + ->maxLength('protocol_number', 255) + ->requirePresence('protocol_number', 'create') + ->notEmptyString('protocol_number'); + + $validator + ->date('protocol_date') + ->requirePresence('protocol_date', 'create') + ->notEmptyDate('protocol_date'); + + $validator + ->scalar('recipient') + ->maxLength('recipient', 255) + ->requirePresence('recipient', 'create') + ->notEmptyString('recipient'); + + $validator + ->scalar('sender') + ->maxLength('sender', 255) + ->requirePresence('sender', 'create') + ->notEmptyString('sender'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + + return $rules; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 11; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php new file mode 100644 index 0000000..00c5a0d --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php @@ -0,0 +1,70 @@ +setTable('water_drawing_paperwork_statuses'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + ]); + $this->hasMany('WaterDrawingPaperworkHistories', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php new file mode 100644 index 0000000..4ae8cb2 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php @@ -0,0 +1,383 @@ +setTable('water_drawing_paperworks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworkStatuses', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingArticles', [ + 'foreignKey' => 'water_drawing_article_id', + 'joinType' => 'LEFT', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('DrarUsers', [ + 'className' => 'Users', + 'foreignKey' => 'drar_user_id', + 'joinType' => 'LEFT', + ]); + $this->belongsTo('GcUsers', [ + 'className' => 'Users', + 'foreignKey' => 'gc_user_id', + 'joinType' => 'LEFT', + ]); + $this->hasMany('ApplicantsWaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingAntimafiaCertificationRequests', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingFees', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingPaperworkHistories', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasMany('WaterDrawingDerivations', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingReturnPoints', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingPaperworkPecs', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->belongsToMany('Applicants', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'targetForeignKey' => 'applicant_id', + 'joinTable' => 'applicants_water_drawing_paperworks', + 'dependent' => true, + 'cascadeCallbacks' => true, + 'sort' => ['is_primary_applicant' => 'DESC'], + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_paperwork_status_id') + ->requirePresence('water_drawing_paperwork_status_id', 'create') + ->notEmptyString('water_drawing_paperwork_status_id'); + + $validator + ->date('from_date') + ->allowEmptyDate('from_date'); + + $validator + ->date('to_date') + ->allowEmptyDate('to_date'); + + $validator + ->scalar('gurs_reference') + ->maxLength('gurs_reference', 255) + ->allowEmptyString('gurs_reference'); + + $validator + ->scalar('authorisation_type') + ->maxLength('authorisation_type', 255) + ->allowEmptyString('authorisation_type'); + + $validator + ->scalar('concession_decree_number') + ->maxLength('concession_decree_number', 255) + ->allowEmptyString('concession_decree_number'); + + $validator + ->date('release_date') + ->allowEmptyDate('release_date'); + + $validator + ->integer('concession_duration') + ->allowEmptyString('concession_duration'); + + $validator + ->date('expiration_date') + ->allowEmptyDate('expiration_date'); + + $validator + ->scalar('first_istance') + ->maxLength('first_istance', 255) + ->allowEmptyString('first_istance'); + + $validator + ->scalar('takeover') + ->maxLength('takeover', 255) + ->allowEmptyString('takeover'); + + $validator + ->integer('year') + ->allowEmptyString('year'); + + $validator + ->scalar('fee_payment_certificate') + ->maxLength('fee_payment_certificate', 255) + ->allowEmptyString('fee_payment_certificate'); + + $validator + ->integer('initial_static_level_water') + ->allowEmptyString('initial_static_level_water'); + + $validator + ->date('initial_static_level_water_date') + ->allowEmptyDate('initial_static_level_water_date'); + + $validator + ->integer('static_level_water') + ->allowEmptyString('static_level_water'); + + $validator + ->date('static_level_water_date') + ->allowEmptyDate('static_level_water_date'); + + $validator + ->scalar('authority_province') + ->maxLength('authority_province', 255) + ->allowEmptyString('authority_province'); + + $validator + ->scalar('authority_identification_code_civil_engineering_office') + ->maxLength('authority_identification_code_civil_engineering_office', 255) + ->allowEmptyString('authority_identification_code_civil_engineering_office'); + + $validator + ->scalar('authority_identification_code_derivation_department_water_waste') + ->maxLength('authority_identification_code_derivation_department_water_waste', 255) + ->allowEmptyString('authority_identification_code_derivation_department_water_waste'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('protocol_number') + ->maxLength('protocol_number', 255) + ->allowEmptyString('protocol_number'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_status_id', 'WaterDrawingPaperworkStatuses'), ['errorField' => 'water_drawing_paperwork_status_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('drar_user_id', 'DrarUsers'), ['errorField' => 'drar_user_id']); + $rules->add($rules->existsIn('gc_user_id', 'GcUsers'), ['errorField' => 'gc_user_id']); + $rules->add($rules->isUnique(['authority_identification_code_civil_engineering_office', 'deleted']), ['errorField' => 'authority_identification_code_civil_engineering_office', 'message' => __('Codice identificativo Concessione Ufficio Genio civile esistente.')]); + //controllo sul codice identificativo della pratica GC + /*$rules->add(function ($entity, $options){ + if($entity->authority_identification_code_civil_engineering_office == ''){ + return true; + } + return preg_match("/^[a-zA-Z]{2}[0-9]{4}$/", $entity->authority_identification_code_civil_engineering_office) == 1; + }, + 'authority_identification_code_civil_engineering_office', + [ + 'errorField' => 'authority_identification_code_civil_engineering_office', + 'message' => __('Formato del codice errato. Rispettare il seguente formato AA0000.') + ]);*/ + $rules->add(function ($entity, $options){ + if($entity->authority_identification_code_derivation_department_water_waste == ''){ + return true; + } + return (preg_match("/^[a-zA-Z]{2}[0-9]{4}$/", $entity->authority_identification_code_derivation_department_water_waste) == 1); + }, + 'authority_identification_code_derivation_department_water_waste', + [ + 'errorField' => 'authority_identification_code_derivation_department_water_waste', + 'message' => __('Formato del codice errato. Rispettare il seguente formato AA0000.') + ]); + + $rules->add(function ($entity, $options) { + $countiesTable = $this->fetchTable("Counties"); + if (!empty($entity->authority_province)) { + $provinceField = strlen($entity->authority_province) === 2 ? 'sigla' : 'den_uts'; + $exists = $countiesTable->exists([$provinceField => $entity->authority_province]); + if (!$exists) { + return false; + } + } + + return true; + }, 'validProvince', [ + 'errorField' => 'authority_province', + 'message' => 'La provincia selezionata non è valida.' + ]); + + return $rules; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 9; + + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare il punto di prelievo/derivazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geom'] = $data['feature_collection']; + } + } + + public function afterSave(EventInterface $event, EntityInterface $entity, \ArrayObject $options){ + $data = (object)[]; + $data->water_drawing_paperwork_id = $entity->id; + $logged_user = Router::getRequest()->getAttribute('identity'); + if ($logged_user) $data->notification_user_id = $logged_user->id; + IntendedUseVegetationCheckCommandSender::sendMessage($data); + } + + /** + * checkAttachments + * + * @param Array $attachments_data + * @return Array + */ + public function checkAttachments($data) { + $files = 0; + $error_message = []; + if(!isset($data['authority_identification_code_civil_engineering_office']) || $data['authority_identification_code_civil_engineering_office'] == '') return [ __('Il codice della pratica da parte del genio civile non è impostato.')]; + foreach($data['attachments'] as $key => $attachments){ + foreach($attachments as $attachment_obj){ + $attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($attachment_obj); + if($attachment['error'] == 0){ + $files++; + switch($key){ + case 'DV': + $supposedFileName = $data['authority_identification_code_civil_engineering_office'] . '.pdf'; + break; + case 'DUEA': + $supposedFileName = $data['authority_identification_code_civil_engineering_office'] . '_2A.pdf'; + break; + default: + $supposedFileName = $data['authority_identification_code_civil_engineering_office'] . '_' . $key . '.pdf'; + } + + if(strtoupper($supposedFileName) != strtoupper($attachment['name'])) $error_message[] = __('Il file "{0}", nella sezione {1}, non ha il nome del file corretto. Il nome corretto dell\'allegato è "{2}". ', $attachment['name'], $key, $supposedFileName); + } + } + } + if($files == 0) $error_message[] = __('Non hai inserito il numero di file necessari.'); + return $error_message; + } + + public function can_index(User $user, Array &$options): Bool + { + if (!$user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) { + $options['error']['capabilities'] = ['documentation.water_drawing_paperworks.view']; + return false; + } + return true; + } + + public function applySearchParams(Query $query, Array $params): Query + { + $search_params = [ + 'cod' => 'WaterDrawingPaperworks.authority_identification_code_civil_engineering_office', + 'cod_drar' => 'WaterDrawingPaperworks.authority_identification_code_derivation_department_water_waste', + 'province' => 'WaterDrawingPaperworks.authority_province', + 'surname' => 'Applicants.surname' + ]; + + $searck_keys = array_keys($search_params); + + $search_conditions = collection($params) + ->filter(function ($paramValue, $paramKey) use ($searck_keys) { + return in_array($paramKey, $searck_keys); + }) + ->map(function ($paramValue, $paramKey) use ($search_params) { + return [$search_params[$paramKey] => $paramValue]; + }) + ->reduce(function ($acc, $search_condition) { + $acc[] = $search_condition; + return $acc; + }, []); + + if (!empty($search_conditions)) { + $query->where($search_conditions); + } + return $query; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php new file mode 100644 index 0000000..2d48ca4 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_payment_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingPayments', [ + 'foreignKey' => 'water_drawing_payment_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php new file mode 100644 index 0000000..0645ea6 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php @@ -0,0 +1,149 @@ +setTable('water_drawing_payments'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('WaterDrawingFees', [ + 'foreignKey' => 'water_drawing_fee_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaymentTypes', [ + 'foreignKey' => 'water_drawing_payment_type_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_fee_id') + ->requirePresence('water_drawing_fee_id', 'create') + ->notEmptyString('water_drawing_fee_id'); + + $validator + ->integer('water_drawing_payment_type_id') + ->requirePresence('water_drawing_payment_type_id', 'create') + ->notEmptyString('water_drawing_payment_type_id'); + + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + $validator + ->numeric('amount') + ->requirePresence('amount', 'create') + ->notEmptyString('amount'); + + $validator + ->date('payment_date') + ->requirePresence('payment_date', 'create') + ->notEmptyString('payment_date'); + + $validator + ->scalar('payment_number') + ->maxLength('payment_number', 255) + ->requirePresence('payment_number', 'create') + ->notEmptyString('payment_number'); + + $validator + ->scalar('notes') + ->maxLength('notes', 4294967295) + ->allowEmptyString('notes'); + + $validator + ->numeric('receipt_amount') + ->allowEmptyString('receipt_amount'); + + $validator + ->date('receipt_date') + ->allowEmptyString('receipt_date'); + + $validator + ->scalar('receipt_number') + ->maxLength('receipt_number', 255) + ->allowEmptyString('receipt_number'); + + $validator + ->scalar('applicant_tax_code') + ->maxLength('applicant_tax_code', 4294967295) + ->allowEmptyString('applicant_tax_code'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_fee_id', 'WaterDrawingFees'), ['errorField' => 'water_drawing_fee_id']); + $rules->add($rules->existsIn('water_drawing_payment_type_id', 'WaterDrawingPaymentTypes'), ['errorField' => 'water_drawing_payment_type_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add(function ($entity, $options){ + if(!isset($entity->receipt_date)) return true; + return ($entity->payment_date <= $entity->receipt_date); + }, ['errorField' => 'receipt_date', 'message' => __('La data di quietanza non può essere antecedente alla data di pagamento.')]); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php new file mode 100644 index 0000000..680bdd7 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php @@ -0,0 +1,120 @@ +setTable('water_drawing_return_points'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('latitude') + ->maxLength('latitude', 255) + ->allowEmptyString('latitude'); + + $validator + ->scalar('longitude') + ->maxLength('longitude', 255) + ->allowEmptyString('longitude'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->allowEmptyString('district'); + + $validator + ->integer('cadastral_sheet') + ->allowEmptyString('cadastral_sheet'); + + $validator + ->integer('cadastral_parcel') + ->allowEmptyString('cadastral_parcel'); + + $validator + ->integer('water_drawing_paperwork_id') + ->allowEmptyString('water_drawing_paperwork_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + + return $rules; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare il punto di restituzione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geom'] = $data['feature_collection']; + } + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php new file mode 100644 index 0000000..0a11497 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_tool_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingMeters', [ + 'foreignKey' => 'water_drawing_tool_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php new file mode 100644 index 0000000..b51d036 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php @@ -0,0 +1,67 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\WaterDrawingWateringSystem findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\WaterDrawingWateringSystem> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem> deleteManyOrFail(iterable $entities, array $options = []) + */ +class WaterDrawingWateringSystemsTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('water_drawing_watering_systems'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_watering_system_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/View/AjaxView.php b/idrocap_wa/src/View/AjaxView.php new file mode 100644 index 0000000..dd9d7d9 --- /dev/null +++ b/idrocap_wa/src/View/AjaxView.php @@ -0,0 +1,46 @@ +response = $this->response->withType('ajax'); + } +} diff --git a/idrocap_wa/src/View/AppView.php b/idrocap_wa/src/View/AppView.php new file mode 100644 index 0000000..a4e335a --- /dev/null +++ b/idrocap_wa/src/View/AppView.php @@ -0,0 +1,52 @@ +addHelper('Html');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + $this->initializeCakeLte(); + $this->addHelper('Sections'); + $this->addHelper('Menu'); + $this->addHelper('Breadcrumb'); + $this->addHelper('Notifications'); + } +} diff --git a/idrocap_wa/src/View/Cell/.gitkeep b/idrocap_wa/src/View/Cell/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/src/View/Cell/DistrictProvinceCell.php b/idrocap_wa/src/View/Cell/DistrictProvinceCell.php new file mode 100644 index 0000000..9061ec6 --- /dev/null +++ b/idrocap_wa/src/View/Cell/DistrictProvinceCell.php @@ -0,0 +1,68 @@ +autoFillTargetEnabled) && $provinceCellConfig->autoFillTargetEnabled && empty($provinceCellConfig?->autoFillTargetId); + if ($autoFillIsMisconfigured) { + throw new Exception("autoFillTargetId must be set when autoFillTargetEnabled is true"); + } + + $viewVars = []; + + /** + * Controllo che in mapConfig abbiamo un array di codeReg e che la specifica region + * sia effettivamente presente. + */ + $codeReg = ProvinceDistrictFieldHelper::getCodeRegByRegion(Regions::SICILY); + $viewVars["codReg"] = $codeReg; + + if ($provinceCellConfig) { + $viewVars["provinces"] = $this->fetchTable('Counties')->getCountiesByRegion($codeReg, $provinceCellConfig); + $viewVars["provinceCellConfig"] = $provinceCellConfig; + } + + if ($districtCellConfig) { + $viewVars["codReg"] = $codeReg; + $viewVars["districtCellConfig"] = $districtCellConfig; + } + + $this->set($viewVars); + } +} diff --git a/idrocap_wa/src/View/Cell/FilterInputCell.php b/idrocap_wa/src/View/Cell/FilterInputCell.php new file mode 100644 index 0000000..d662de2 --- /dev/null +++ b/idrocap_wa/src/View/Cell/FilterInputCell.php @@ -0,0 +1,51 @@ +Cell('FilterInput', [ + * filter_id, // Int -> id fel filtro da recuperare in table filters + * value, // ?Any -> il valore impostato dall'utente per il tipo di filtro + * ]); + */ +class FilterInputCell extends Cell +{ + protected array $_validCellOptions = []; + + /** + * display + * + * @param Int $filter_id + * @param ?String $value + * @return void + */ + public function display(Int $filter_id, ?String $value = null) + { + $filter = $this->fetchTable('Filters')->get($filter_id); + + if ($filter->filter_type == 'class') { + $table_name = $this->fetchTable($filter->class_name)->getAlias(); + $display_field = $this->fetchTable($filter->class_name)->getDisplayField(); + $order_clause = json_decode($filter->order_clause ?? '', true) ?? ["$table_name.$display_field" => 'ASC']; + $options = $this->fetchTable($filter->class_name)->find('list')->order($order_clause); + } + + if ($filter->filter_type == 'bool') { + $options = [0 => __('NO'), 1 => __('SI')]; + } + + $this->set('label', $filter->description); + $this->set('name', 'filter_id_' . $filter->id); + $this->set('type', in_array($filter->filter_type, ['class', 'bool']) ? 'select' : 'text'); + $this->set('additional_classes', $filter->filter_type == 'date' ? ' jixeldaterangepicker' : ''); + $this->set('options', $options ?? null); + $this->set('value', $value ?? null); + } +} diff --git a/idrocap_wa/src/View/Cell/FiltersCell.php b/idrocap_wa/src/View/Cell/FiltersCell.php new file mode 100755 index 0000000..d225eb9 --- /dev/null +++ b/idrocap_wa/src/View/Cell/FiltersCell.php @@ -0,0 +1,50 @@ +Cell('Filters', [ + * header_title, // String -> titolo da visualizzare nell'header del collapsable + * ]); + * + */ +class FiltersCell extends Cell +{ + protected array $_validCellOptions = []; + + /** + * display + * + * @param String $header_title + * @return void + */ + public function display(String $header_title) + { + $logged_user = Router::getRequest()->getAttribute('identity'); + $logged_user_id = $logged_user->id ?? 0; + $controller = Router::getRequest()->getParam('controller'); + $action = Router::getRequest()->getParam('action'); + $controller_action_category = "$controller-$action"; + $filter_session_key = "filters-$logged_user_id-$controller-$action"; + $filters = Router::getRequest()->getSession()->read($filter_session_key); + + $available_filters = $this->fetchTable('Filters')->find('list') + ->where(['Filters.controller_action_category' => $controller_action_category]) + ->order(['Filters.order_number' => 'ASC']); + + if (!$logged_user->sys_admin) { + $available_filters = $available_filters->where(['Filters.sys_admin_only' => false]); + } + + $this->set('filters', $filters ?? []); + $this->set('available_filters', $available_filters); + $this->set('header_title', $header_title); + } +} diff --git a/idrocap_wa/src/View/Cell/IntendedUsesCell.php b/idrocap_wa/src/View/Cell/IntendedUsesCell.php new file mode 100644 index 0000000..5569264 --- /dev/null +++ b/idrocap_wa/src/View/Cell/IntendedUsesCell.php @@ -0,0 +1,33 @@ +getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('intended_use_item_block', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + } +} diff --git a/idrocap_wa/src/View/Cell/MapCell.php b/idrocap_wa/src/View/Cell/MapCell.php new file mode 100755 index 0000000..aa629ee --- /dev/null +++ b/idrocap_wa/src/View/Cell/MapCell.php @@ -0,0 +1,234 @@ +Cell('Map', [ + [-1], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Evento'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => true, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'feature_collection' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'feature-collection-custom1', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'feature_collection_custom1', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Collezione di geometrie'), + ], + 'longitude' => [ // Array = null -> null/[] = il campo longitude non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude-custom2', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude_custom2', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Longitudine'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo latitude non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude-custom3', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude_custom3', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Latitudine'), + ], + 'coordinates' => [ // Array = null -> null/[] = il campo coordinates non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'coordinates-custom4', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'coordinates_custom4', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinate (Longitudine Latitudine)'), + ], + 'cap' => [ // Array = null -> null/[] = il campo cap non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'cap', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'cap', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Cap'), + ], + 'province' => [ // Array = null -> null/[] = il campo province non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'province', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'province', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Provincia'), + ], + 'district_code' => [ // Array = null -> null/[] = il campo district_code non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district-code', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district_code', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Codice ISTAT'), + ], + 'district' => [ // Array = null -> null/[] = il campo district non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo address non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'address', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'address', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Indirizzo'), + ], + 'description' => [ // Array = null -> null/[] = il campo description non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'description', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'description', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Descrizione luogo'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'table_name' => 'geo.rw_watersheds', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'id' => 'ws-id', + 'swbcode' => 'swbcode' + ], + ], + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'COD_COMUNE' => 'cadastral-code', + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + */ + + /** + * display + * + * @param ?Array $layer_ids + * @param Bool $get_current_position + * @param ?Array $tools + * @param ?Int $zoom_to_layer_with_id + * @return void + */ + public function display(?Array $layer_ids = null, Bool $get_current_position = false, ?Array $tools = null, ?Int $zoom_to_layer_with_id = null) + { + $layers = []; + + if (is_array($layer_ids)) { + $layers = $this->fetchTable('Maps')->find(); + + if (isset($layer_ids) && is_array($layer_ids) && count($layer_ids) > 0) { + $layers->where(['Maps.id IN' => $layer_ids]); + } + + $layers = $layers->all(); + + $layers = $layers->map(function ($value, $key) use ($zoom_to_layer_with_id) { + $value->style = json_decode($value->style ?? ''); + $value->zoom_to_layer = isset($zoom_to_layer_with_id) && $value->id == $zoom_to_layer_with_id; + return $value; + }); + + $found_layers = $layers->reduce(function ($acc, $layer) { + $acc[$layer->id][$layer->language_code] = $layer; + return $acc; + }, []); + + $locale = I18n::getLocale(); + + $layers = collection($found_layers) + ->reduce(function ($acc, $found_layer) use ($locale) { + $acc[] = isset($found_layer[$locale]) ? $found_layer[$locale] : $found_layer['it']; + return $acc; + }, []); + } + + $this->set('layers', $layers); + $this->set('get_current_position', (isset($get_current_position) && $get_current_position)); + $this->set('tools', is_array($tools) && !empty($tools)); + $this->set('drawing_layer_name', !empty($tools['drawing_layer_name']) ? $tools['drawing_layer_name'] : __('Geometrie disegnate')); + $this->set('geocoding', isset($tools['geocoding']) && $tools['geocoding']); + $this->set('point', isset($tools['point']) && $tools['point']); + $this->set('multiple_points', !(isset($tools['geocoding']) && $tools['geocoding']) && isset($tools['multiple_points']) && $tools['multiple_points']); + $this->set('polygon', isset($tools['polygon']) && $tools['polygon']); + $this->set('circle', isset($tools['circle']) && $tools['circle']); + $this->set('delete_geometry', isset($tools['delete_geometry']) && $tools['delete_geometry']); + $this->set('feature_collection', $tools['fields']['feature_collection'] ?? false); + $this->set('longitude', $tools['fields']['longitude'] ?? false); + $this->set('latitude', $tools['fields']['latitude'] ?? false); + $this->set('coordinates', $tools['fields']['coordinates'] ?? false); + $this->set('cap', $tools['fields']['cap'] ?? false); + $this->set('province', $tools['fields']['province'] ?? false); + $this->set('district_code', $tools['fields']['district_code'] ?? false); + $this->set('district', $tools['fields']['district'] ?? false); + $this->set('address', $tools['fields']['address'] ?? false); + $this->set('description', $tools['fields']['description'] ?? false); + $this->set('geo_resources', $tools['geo_resources'] ?? false); + } +} diff --git a/idrocap_wa/src/View/CustomCsvView.php b/idrocap_wa/src/View/CustomCsvView.php new file mode 100644 index 0000000..fd65f46 --- /dev/null +++ b/idrocap_wa/src/View/CustomCsvView.php @@ -0,0 +1,100 @@ +getConfig('setSeparator'); + if ($setSeparator) { + fwrite($fp, 'sep=' . $setSeparator . "\n"); + } + } else { + ftruncate($fp, 0); + } + + $null = $this->getConfig('null'); + if ($null) { + foreach ($row as &$field) { + if ($field === null) { + $field = $null; + } + } + } + + $delimiter = $this->getConfig('delimiter'); + $enclosure = $this->getConfig('enclosure'); + $newline = $this->getConfig('newline'); + + $row = str_replace(["\r\n", "\n", "\r"], $newline, $row); + if ($enclosure === '') { + // fputcsv does not supports empty enclosure + if (fputs($fp, implode($delimiter, $row) . "\n") === false) { + return false; + } + } else { + if (fputcsv($fp, $row, $delimiter, $enclosure, "\\") === false) { + return false; + } + } + + rewind($fp); + + $csv = ''; + while (($buffer = fgets($fp, 4096)) !== false) { + $csv .= $buffer; + } + + $eol = $this->getConfig('eol'); + if ($eol !== "\n") { + $csv = str_replace("\n", $eol, $csv); + } + + $dataEncoding = $this->getConfig('dataEncoding'); + $csvEncoding = $this->getConfig('csvEncoding'); + if ($dataEncoding !== $csvEncoding) { + $extension = $this->getConfig('transcodingExtension'); + if ($extension === static::EXTENSION_ICONV) { + $csv = iconv($dataEncoding, $csvEncoding, $csv); + } elseif ($extension === static::EXTENSION_MBSTRING) { + $csv = mb_convert_encoding($csv, $csvEncoding, $dataEncoding); + } + } + + // BOM must be added after encoding + $bom = $this->getConfig('bom'); + if ($bom && $this->isFirstBom) { + $csv = $this->getBom($csvEncoding) . $csv; + $this->isFirstBom = false; + } + + return $csv; + } +} diff --git a/idrocap_wa/src/View/Helper/BreadcrumbHelper.php b/idrocap_wa/src/View/Helper/BreadcrumbHelper.php new file mode 100644 index 0000000..a0124ea --- /dev/null +++ b/idrocap_wa/src/View/Helper/BreadcrumbHelper.php @@ -0,0 +1,67 @@ + + */ + protected array $_defaultConfig = []; + + public array $helpers = ['Breadcrumbs']; + + /** + * output + * + * @param String $breadcrumb + * @return String + */ + private function output(String $breadcrumb) + { + return << +
+ $breadcrumb +
+ + EOD; + } + + /** + * render + * + * @param Array $items + * @return String + */ + public function render(Array $items): String + { + $this->Breadcrumbs->setTemplates([ + 'wrapper' => '{{content}}', + 'item' => ' {{title}}{{separator}}', + 'itemWithoutLink' => ' {{title}}{{separator}}', + 'separator' => '{{separator}}', + ]); + + $items = collection($items) + ->map(function ($item) { + return ['title' => $item['title'], 'url' => $item['url'] ?? null, 'options' => ['innerAttrs' => ['class' => $item['icon'] ?? '']]]; + }) + ->toArray(); + + $this->Breadcrumbs->add($items); + + $breadcrumb = $this->Breadcrumbs->render(['class' => 'float-sm-right']); + + return $this->output($breadcrumb); + } +} diff --git a/idrocap_wa/src/View/Helper/MenuHelper.php b/idrocap_wa/src/View/Helper/MenuHelper.php new file mode 100644 index 0000000..87fb82d --- /dev/null +++ b/idrocap_wa/src/View/Helper/MenuHelper.php @@ -0,0 +1,108 @@ + + */ + protected array $_defaultConfig = []; + + public array $helpers = ['Form', 'Html']; + + /** + * makeSingleItem + * + * @param String $title + * @param ?String $icon + * @param String $link + * @param ?String $confirm + * @param String $method + * @return String + */ + private function makeSingleItem(String $title, String|Null $icon, String $link, ?String $confirm = null, String $method = 'GET'): String + { + $fa_icon = !empty($icon) ? " fa fa-$icon" : ""; + + if (!empty($confirm) || $method == 'POST') { + $form_title = << +

$title

+ EOD; + + $form_link = $method == 'POST' ? $this->Form->postLink($form_title, $link, ['confirm' => $confirm, 'escape' => false, 'class' => 'nav-link']) : $this->Html->link($form_title, $link, ['confirm' => $confirm, 'escape' => false, 'class' => 'nav-link']); + } else { + $form_link = << + +

$title

+ + EOD; + } + + return << + $form_link + + EOD; + } + + /** + * makeItemWithSubItems + * + * @param String $title + * @param ?String $icon + * @param Array $items + * @return String + */ + private function makeItemWithSubItems(String $title, String|Null $icon, Array $items): String + { + $menu_items = implode("", collection($items)->map(function ($item) { return isset($item['link']) ? $this->makeSingleItem($item['title'], $item['icon'], $item['link'], $item['confirm'] ?? null, $item['method'] ?? 'GET') : $this->makeItemWithSubItems($item['title'], $item['icon'], $item['menu_items']); })->toArray()); + + $fa_icon = !empty($icon) ? " fa fa-$icon" : ""; + + return << + + +

+ $title + +

+
+ + + EOD; + } + + /** + * create + * + * @param Array $menu_items + * @return String + */ + public function create(Array $menu_items): String + { + $output = ''; + + foreach ($menu_items as $menu_item) { + if (isset($menu_item['link'])) { + $output.= $this->makeSingleItem($menu_item['title'], $menu_item['icon'], $menu_item['link'], $menu_item['confirm'] ?? null, $menu_item['method'] ?? 'GET'); + } else { + $output.= $this->makeItemWithSubItems($menu_item['title'], $menu_item['icon'], $menu_item['menu_items']); + } + } + return $output; + } +} diff --git a/idrocap_wa/src/View/Helper/NotificationsHelper.php b/idrocap_wa/src/View/Helper/NotificationsHelper.php new file mode 100644 index 0000000..a457c2d --- /dev/null +++ b/idrocap_wa/src/View/Helper/NotificationsHelper.php @@ -0,0 +1,87 @@ + + */ + protected array $_defaultConfig = []; + + /** + * makeNotification + * + * @param String $id + * @param String $icon + * @param String $title + * @param String $time_ago + * @param String $body + * @return String + */ + private function makeNotification(String $id, String $icon, String $title, String $time_ago, String $body): String + { + $title = strlen($title) > 35 ? substr($title, 0, 32) . '...' : $title; + return << + + $title + $time_ago +

$body

+
+ EOD; + } + + /** + * makeNotificationList + * + * @param String $user_notifications_count + * @param String $notification_items + * @return String + */ + private function makeNotificationList(String $user_notifications_count, String $notification_items): String + { + $user_notifications_count_badge = $user_notifications_count > 0 ? '' . $user_notifications_count . '' : ''; + $notifications_header = '' . __('Nuove notifiche: {0}', $user_notifications_count) . ''; + $notifications_footer = $user_notifications_count > 0 ? '' . __('Segna tutte le notifiche come lette') . '' : ''; + + return << + + + $user_notifications_count_badge + + + + EOD; + } + + /** + * create + * + * @param Array $menu_sections + * @return String + */ + public function create(Array $notifications): String + { + $notification_items = ''; + foreach ($notifications as $notification) { + $notification_items.= $this->makeNotification((String)$notification['id'], $notification['icon'], $notification['title'], $notification['time_ago'], $notification['body']); + } + return $this->makeNotificationList((String)count($notifications), $notification_items); + } +} diff --git a/idrocap_wa/src/View/Helper/SectionsHelper.php b/idrocap_wa/src/View/Helper/SectionsHelper.php new file mode 100644 index 0000000..d99a80d --- /dev/null +++ b/idrocap_wa/src/View/Helper/SectionsHelper.php @@ -0,0 +1,55 @@ + + */ + protected array $_defaultConfig = []; + + /** + * makeSection + * + * @param String $title + * @param ?String $icon + * @param Int $id + * @return String + */ + private function makeSection(String $title, String|Null $icon, Int $id): String + { + $url = Router::getRequest()->getPath(); + return << + + + + + EOD; + } + + /** + * create + * + * @param Array $menu_sections + * @return String + */ + public function create(Array $menu_sections): String + { + $output = ''; + foreach ($menu_sections as $menu_section) { + $output.= $this->makeSection($menu_section['title'], $menu_section['icon'], $menu_section['id']); + } + return $output; + } +} diff --git a/idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php b/idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php new file mode 100644 index 0000000..10ac5af --- /dev/null +++ b/idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php @@ -0,0 +1,163 @@ +getSession()->write("oidc.oidc_state", $state); + + // Construct the authorization URL + $params = [ + 'state' => $state, + 'response_type' => 'code', + 'client_id' => $clientId, + 'scope' => $scopes, + 'redirect_uri' => $redirectUri, + ]; + + $authRequestUrl = $authUrl . '?' . http_build_query($params); + // Redirect the user to the OpenID Provider's authorization page + header("Location: $authRequestUrl"); + exit(); + } + + /** + * get_access_token + * + * This method performs a POST request to the IdP tokenUrl endpoint in order to obtain both id and access tokens + * + * @param String $tokenUrl + * @param String $issuer + * @param String $clientId + * @param Null|String $clientSecret + * @param String $redirectUri + * @throws Exception + * @return String + */ + public static function get_access_token(String $tokenUrl, String $issuer, String $clientId, Null|String $clientSecret, String $redirectUri): String + { + // Check if the state parameter matches the stored one to prevent CSRF + if (Router::getRequest()->getSession()->read("oidc.oidc_state") !== Router::getRequest()->getQuery('state')) { + throw new \Exception("oidc_state mismatch!"); + } + + // Retrieve the authorization code from the callback + $code = Router::getRequest()->getQuery('code'); + Router::getRequest()->getSession()->write('oidc.auth_code', $code); + + // Exchange the authorization code for tokens + $data = [ + 'grant_type' => 'authorization_code', + 'code' => $code, + 'client_id' => $clientId, + 'redirect_uri' => $redirectUri, + ]; + + if (!empty($clientSecret)) $data['client_secret'] = $clientSecret; + + // Use cURL to send the POST request to the token endpoint + $ch = curl_init($tokenUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']); + $response = curl_exec($ch); + $errno = curl_errno($ch); + if($errno) { + $error_message = curl_strerror($errno); + throw new \Exception("Error retrieving access token from $tokenUrl: $errno - $error_message"); + } + curl_close($ch); + + // Decode the response, which contains the ID token and Access Token + $responseData = is_string($response) && strlen($response) > 0 ? json_decode($response, true) : ''; + if (empty($responseData)) throw new \Exception("Unexpected or malformed Issuer response"); + Router::getRequest()->getSession()->write("oidc.id_token", $responseData['id_token'] ?? ''); + Router::getRequest()->getSession()->write("oidc.access_token", $responseData['access_token'] ?? ''); + + $id_token_array = explode('.', $responseData['id_token'] ?? ''); + $decodedPayload = !empty($id_token_array[1]) && is_string($id_token_array[1]) && strlen($id_token_array[1]) > 0 ? json_decode(base64_decode($id_token_array[1]), true) : ''; + if (empty($decodedPayload)) throw new \Exception("Error decoding ID Token"); + if (empty($decodedPayload['iss'])) throw new \Exception("Issuer data is missing"); + if ($decodedPayload['iss'] !== $issuer) throw new \Exception("Invalid Issuer"); + if (empty($decodedPayload['aud'])) throw new \Exception("Audience data is missing"); + $audience_array = is_array($decodedPayload['aud']) ? $decodedPayload['aud'] : [$decodedPayload['aud']]; + if (!in_array($clientId, $audience_array)) throw new \Exception("Invalid Audience"); + if (empty($decodedPayload['exp'])) throw new \Exception("ID Token expiration information is missing"); + if ($decodedPayload['exp'] < time()) throw new \Exception("ID token has expired"); + return $responseData['access_token'] ?? ''; + } + + /** + * get_user_info + * + * This method performs a GET request to the IdP userInfoUrl endpoint using previously retrieved access token + * + * @param String $userInfoUrl + * @param String $access_token + * @throws Exception + * @return String + */ + public static function get_user_info(String $userInfoUrl, String $userinfo_claim_key, String $access_token): array + { + $ch = curl_init($userInfoUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $access_token, + ]); + $userInfoResponse = curl_exec($ch); + $errno = curl_errno($ch); + if($errno) { + $error_message = curl_strerror($errno); + throw new \Exception("Error retrieving user info from $userInfoUrl: $errno - $error_message"); + } + curl_close($ch); + + // Decode the response, which contains all user info + $decodedUserInfoResponse = is_string($userInfoResponse) && strlen($userInfoResponse) > 0 ? json_decode($userInfoResponse, true) : ''; + if (empty($decodedUserInfoResponse)) throw new \Exception("Unexpected or malformed User info response"); + if (empty($decodedUserInfoResponse[$userinfo_claim_key])) throw new \Exception("User info '$userinfo_claim_key' attribute is missing"); + return $decodedUserInfoResponse; + } + + /** + * logout + * + * @param String $endSessionUrl + * @param String $clientId + * @param String $postLogoutRedirectUri + * @return void + */ + public static function logout(String $endSessionUrl, String $clientId, String $postLogoutRedirectUri) + { + $params = [ + 'client_id' => $clientId, + 'state' => Router::getRequest()->getSession()->read("oidc.oidc_state"), + 'post_logout_redirect_uri' => $postLogoutRedirectUri, // Where to redirect after logout + ]; + + // Construct the logout URL with query parameters + $logoutUrl = $endSessionUrl . '?' . http_build_query($params); + + Router::getRequest()->getSession()->destroy(); + // Redirect to the OpenID Provider's logout page + header('Location: ' . $logoutUrl); + exit(); + } +} diff --git a/idrocap_wa/src/WGS/FileStorage/FileStorage.php b/idrocap_wa/src/WGS/FileStorage/FileStorage.php new file mode 100755 index 0000000..e002896 --- /dev/null +++ b/idrocap_wa/src/WGS/FileStorage/FileStorage.php @@ -0,0 +1,14 @@ +namenodeHost = $namenodeHost; + $this->namenodePort = $namenodePort; + $this->namenodeUser = $namenodeUser; + $this->namenodeRpcHost = $namenodeRpcHost; + $this->namenodeRpcPort = $namenodeRpcPort; + $this->hdfs = new \org\apache\hadoop\WebHDFS($this->namenodeHost, $this->namenodePort, $this->namenodeUser, $this->namenodeRpcHost, $this->namenodeRpcPort, true); + } + + /** + * getFile + * + * @param String $path + * @return mixed + */ + public function getFile(String $path) + { + return $this->hdfs->open($path); + } + + /** + * deleteFile + * + * @param String $path + * @return mixed + */ + public function deleteFile(String $path) + { + $this->hdfs->delete($path); + } + + /** + * saveFile + * + * @param String $path + * @param String $tmpPath + * @throws \Exception + * @return mixed + */ + public function saveFile(String $path, String $tmpPath) + { + try + { + $result = $this->hdfs->create($path, $tmpPath); + return $result; + } + catch(\org\apache\hadoop\WebHDFS_Exception $we) + { + throw new \Exception('Unable to save file on HadoopFileStorage: ' . $we->getMessage()); + } + } + + /** + * savePassedFile + * + * @param String $path + * @param String $file + * @return mixed + */ + public function savePassedFile(String $path, String $file) + { + return $this->hdfs->createWithData($path, $file); + } + + /** + * copyFile + * + * @param String $path1 + * @param String $path2 + * @return mixed + */ + public function copyFile(String $path1, String $path2) + { + $file = $this->getFile($path1); + $this->savePassedFile($path2, $file); + } + + /** + * checkIfExists + * + * @param String $path + * @return mixed + */ + public function checkIfExists(String $path) + { + $response = $this->hdfs->getFileStatus($path); + $jsonResponse = json_decode($response); + return !isset($jsonResponse->RemoteException->exception); + } +} diff --git a/idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php b/idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php new file mode 100755 index 0000000..1d41137 --- /dev/null +++ b/idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php @@ -0,0 +1,180 @@ +config = [ + 'version' => 'latest', + 'region' => $region, + 'use_path_style_endpoint' => true, + 'credentials' => [ + 'key' => $accessKey, + 'secret' => $secretKey, + ], + ]; + + if($endpoint != null) + { + $this->config['endpoint'] = $endpoint; + } + + $this->bucket = $bucket; + $this->client = new S3Client($this->config); + + if(!$this->client->doesBucketExist($bucket)) $this->client->createBucket(['Bucket' => $bucket]); + } + + /** + * adaptPath + * + * @param String $path + * @return String + */ + protected function adaptPath($path) + { + return substr(str_replace('/', '_', $path),1); + } + + /** + * getFile + * + * @param String $path + * @return mixed + */ + public function getFile(String $path) + { + $path = $this->adaptPath($path); + $retrive = $this->client->getObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + ]); + + return $retrive['Body']->__toString(); + } + + /** + * deleteFile + * + * @param String $path + * @return mixed + */ + public function deleteFile(String $path) + { + $path = $this->adaptPath($path); + $this->client->deleteObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + ]); + } + + /** + * saveFile + * + * @param String $path + * @param String $tmpPath + * @throws \Exception + * @return mixed + */ + public function saveFile(String $path, String $tmpPath) + { + $path = $this->adaptPath($path); + try + { + $insert = $this->client->putObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + 'SourceFile' => $tmpPath + ]); + + return $insert; + } + catch(\Exception $we) + { + throw new \Exception('Unable to save file on S3MinioFileStorage: ' . $we->getMessage()); + } + } + + /** + * savePassedFile + * + * @param String $path + * @param String $file + * @throws \Exception + * @return mixed + */ + public function savePassedFile(String $path, String $file) + { + $path = $this->adaptPath($path); + try + { + $insert = $this->client->putObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + 'Body' => $file, + ]); + + return $insert; + } + catch(\Exception $we) + { + throw new \Exception('Unable to save file on S3MinioFileStorage: ' . $we->getMessage()); + } + } + + /** + * copyFile + * + * @param String $path1 + * @param String $path2 + * @return mixed + */ + public function copyFile(String $path1, String $path2) + { + $path1 = $this->adaptPath($path1); + $path2 = $this->adaptPath($path2); + $sourceBucket = $this->bucket; + $sourceKeyname = $path1; + + $copy = $this->client->copyObject([ + 'Bucket' => $this->bucket, + 'Key' => $path2, + 'CopySource' => "{$sourceBucket}/{$sourceKeyname}", + ]); + + return $copy; + } + + /** + * checkIfExists + * + * @param String $path + * @return Bool + */ + public function checkIfExists(String $path) + { + $path = $this->adaptPath($path); + return $this->client->doesObjectExist($this->bucket, $path); + } +} + +?> \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Geo/CadastralUtils.php b/idrocap_wa/src/WGS/Geo/CadastralUtils.php new file mode 100644 index 0000000..736a7d6 --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/CadastralUtils.php @@ -0,0 +1,61 @@ +execute($sql_statement)->fetchAll('assoc'); + if (!isset($result[0]['result']) || json_decode($result[0]['result'], true) === null || !isset(json_decode($result[0]['result'], true)['coordinates'])) return null; + $result_object = json_decode($result[0]['result'], true)['coordinates']; + $coordinates = (object)[]; + $coordinates->latitude = $result_object[0]; + $coordinates->longitude = $result_object[1]; + return $coordinates; + } + catch(\Exception $e) { + return null; + } + } + + /** + * isParcelWithinVegetationArea + * + * controlla se la particella specificata, del foglio specificato del comune specificato si interseca o meno con un'area di vegetazione + * + * @param String $cadastral_code + * @param String $sheet + * @param String $parcel + * @return Bool + */ + public static function isParcelWithinVegetationArea(String $cadastral_code, String $sheet, String $parcel): Bool + { + $sql_statement = "select count(*) as result from full_vegetations where st_intersects(SHAPE, (select SHAPE from cadastral_{$cadastral_code}_parcels where nationalcadastralreference = concat((select nationalcadastralzoningreference from cadastral_{$cadastral_code}_sheets where label = '{$sheet}'), '.', '{$parcel}')));"; + + $connection = ConnectionManager::get('geo'); + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return isset($result[0]['result']) && $result[0]['result'] > 0; + } + catch(\Exception $e) { + return false; + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php b/idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php new file mode 100644 index 0000000..865521e --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php @@ -0,0 +1,40 @@ +url = $url; + $this->lon_parameter_name = $lon_parameter_name; + $this->lat_parameter_name = $lat_parameter_name; + } + + /** + * retrieve + * + * @param String $lat + * @param String $lon + * @return Array + */ + public function retrieve(String $lon, String $lat) + { + $http = new Client(); + $response = $http->get($this->url, [$this->lon_parameter_name => $lon, $this->lat_parameter_name => $lat]); + return json_decode($response->getStringBody(), true); + } +} diff --git a/idrocap_wa/src/WGS/Geo/GeoValidation.php b/idrocap_wa/src/WGS/Geo/GeoValidation.php new file mode 100644 index 0000000..698a79b --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/GeoValidation.php @@ -0,0 +1,61 @@ +execute('SELECT st_intersects(st_geomFromGeojson(\''.$testGeometry.'\'),st_geomFromGeojson(\''.json_encode($geometry).'\')) as result') + ->fetchAll('assoc'); + return isset($result[0]['result']) && $result[0]['result']; + } + catch(\Exception $e) { + return false; + } + } + + /** + * checkCadastralCoordinates + * + * chiede a mysql GEO se le coordinate passate costituiscono un punto all'interno del comune, foglio e particella passate + * + * @param String $latitude + * @param String $longitude + * @param String $cadastral_code + * @param String $sheet + * @param String $parcel + * @return Bool + */ + public static function checkCadastralCoordinates(String $latitude, String $longitude, String $cadastral_code, String $sheet, String $parcel): Bool + { + $sql_statement = "select count(*) as result from cadastral_{$cadastral_code}_parcels where nationalcadastralreference = concat((select nationalcadastralzoningreference from cadastral_{$cadastral_code}_sheets where label = '{$sheet}'),'.', '{$parcel}') and st_intersects(SHAPE, st_geomfromtext('POINT({$latitude} {$longitude})',4326));"; + $connection = ConnectionManager::get('geo'); + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return isset($result[0]['result']) && $result[0]['result'] === 1; + } + catch(\Exception $e) { + return false; + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Geo/Geocoding.php b/idrocap_wa/src/WGS/Geo/Geocoding.php new file mode 100644 index 0000000..c9a60e5 --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/Geocoding.php @@ -0,0 +1,84 @@ +get( + $url, + ['type' => 'json'], ['ssl_verify_peer' => false, 'ssl_verify_peer_name' => false] + ); + $http_code = $result->getStatusCode(); + if ($http_code == 200 && $result->getJson() !== null) { + $result = $result->getJson(); + } else { + $result = []; + } + return ['http_code' => $http_code, 'result' => $result]; + } + + /** + * performGeocoding + * + * @param ?String $parameters + * @param ?Array $queryParameters + * @return Array + */ + public static function performGeocoding(?String $parameters = null, ?Array $queryParameters = null) + { + $language_code = substr(I18n::getLocale(), 0, 2); + $status = 'online'; + + $map_config = Configure::read('App.mapConfig'); + $upperLeftBoundLon = $map_config['upperLeftBoundLon']; + $upperLeftBoundLat = $map_config['upperLeftBoundLat']; + $lowerRightBoundLon = $map_config['lowerRightBoundLon']; + $lowerRightBoundLat = $map_config['lowerRightBoundLat']; + + $url = Configure::read('App.urlGeocodingOnline') . "$parameters?accept-language=$language_code&viewbox=$upperLeftBoundLon,$upperLeftBoundLat,$lowerRightBoundLon,$lowerRightBoundLat&bounded=1"; + + foreach ($queryParameters as $key => $value) + { + $url .= "&$key=" . urlencode($value); + } + + if(!Configure::read('App.enableGeocodingOffline') || !Cache::read('geocoding_offline') || (time() - Cache::read('geocoding_offline') > Configure::read('App.offlineTimeout'))) + { + Cache::delete('geocoding_offline'); + $json_result = Geocoding::getJson($url); + } + + if (Configure::read('App.enableGeocodingOffline') && (!isset($json_result) || $json_result['http_code'] != 200 || is_string($json_result['result']))) + { + if(!Cache::read('geocoding_offline')) + { + Cache::write('geocoding_offline', time()); + } + $url = Configure::read('App.urlGeocodingOffline') . "$parameters?accept-language=$language_code&viewbox=$upperLeftBoundLon,$upperLeftBoundLat,$lowerRightBoundLon,$lowerRightBoundLat&bounded=1"; + + foreach($queryParameters as $key => $value) + { + $url .= "&$key=" . urlencode($value); + } + $status = 'offline'; + $json_result = Geocoding::getJson($url); + } + + $result = ['url' => $url, 'status' => $status, 'contents' => $json_result['result'], 'status_code' => ['http_code' => $json_result['http_code']]]; + return $result; + } +} diff --git a/idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php b/idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php new file mode 100644 index 0000000..702cb5a --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php @@ -0,0 +1,57 @@ +connection_name = count($geo_resource_path_array ) > 1 ? $geo_resource_path_array[0] : 'default'; + $this->db_name = count($geo_resource_path_array ) > 1 ? $geo_resource_path_array[0] : 'jixel'; + $this->table_name = $geo_resource_path_array[count($geo_resource_path_array) - 1]; + $this->geometry_name = $geometry_name; + $field_prefix = $this->db_name . '.' . $this->table_name; + $this->select_fields = implode(",", collection($attributes)->map(function ($attribute) use ($field_prefix) { return "$field_prefix.$attribute"; })->toArray()); + } + + /** + * retrieve + * + * @return Array + */ + public function retrieve($feature_collection) + { + $select_fields = $this->select_fields; + $connection_name = $this->connection_name; + $db_name = $this->db_name; + $table_name = $this->table_name; + $geometry_name = $this->geometry_name; + $connection = ConnectionManager::get("$connection_name"); + $sql_statement = "select $select_fields from $db_name.$table_name where st_intersects($db_name.$table_name.$geometry_name, st_geomfromgeojson('$feature_collection'))"; + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return $result; + } + catch(\Exception $e) { + return ['error' => true, 'code' => $e->getCode(), 'message' => $e->getMessage()]; + } + } +} diff --git a/idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php b/idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php new file mode 100644 index 0000000..24eda59 --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php @@ -0,0 +1,65 @@ +setLocation($location); + } + + /** + * setLocation + * + * @param ?Location $location + * @return LocationAttributesRetriever + */ + public function setLocation(?Location $location = null): LocationAttributesRetriever + { + if (empty($location) || get_class($location) != 'App\Model\Entity\Location') { + throw new \Exception('LocationAttributesRetriever/setLocation: Invalid location entity passed!'); + } + + $geometry_collection = json_decode('{"type": "FeatureCollection","features": []}'); + if (isset($location->feature_collection) && json_decode($location->feature_collection) != null) { + $geometry_collection = json_decode($location->feature_collection); + } + if (isset($location->coordinates) && $location->coordinates != '' && json_decode($location->coordinates) == null) { + $geometry_collection->features[] = json_decode('{"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": ['.str_replace(" ", ",", $location->coordinates).']}}'); + } + $this->geometry_collection = json_encode($geometry_collection); + + return $this; + } + + /** + * retrieve + * + * @return Array + */ + public function retrieve() + { + $sql_statement = "select pro_com_t as district_code, comune as district_name, sigla as county_code, den_uts as county_name, den_reg as region, den_rip as area from geo.districts join geo.counties on geo.counties.cod_prov = geo.districts.cod_prov join geo.regions on geo.regions.cod_reg = geo.counties.cod_reg join geo.areas on geo.areas.cod_rip = geo.regions.cod_rip where st_intersects(geo.areas.SHAPE, st_geomfromgeojson('$this->geometry_collection')) and st_intersects(geo.regions.SHAPE, st_geomfromgeojson('$this->geometry_collection')) and st_intersects(geo.counties.SHAPE, st_geomfromgeojson('$this->geometry_collection')) and st_intersects(geo.districts.SHAPE, st_geomfromgeojson('$this->geometry_collection'))"; + $connection = ConnectionManager::get('geo'); + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return $result; + } + catch(\Exception $e) { + return ['error' => true, 'code' => $e->getCode(), 'message' => $e->getMessage()]; + } + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php b/idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php new file mode 100644 index 0000000..d6b8de7 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php @@ -0,0 +1,631 @@ +<è+òàù,.-'; + } + + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; + } + + /** + * generateOneTimePassword + * + * @return String + */ + private static function generateOneTimePassword(): String + { + return time().md5(MessagingHandler::generateRandomString(50)); + } + + /** + * getEventID + * + * @param ?String $co_id + * @param ?String $user_id + * @return String + */ + private static function getEventID(?String $co_id = null, ?String $user_id = null): String + { + $datetime = new \DateTime(); + + if($co_id && $user_id) + { + return $datetime->format('ymdhi') . 'UID' . $user_id . 'COID' . $co_id . 'TS' . substr((string)microtime(), 2, 8); + } + return $datetime->format('ymdhi') . 'LID' . MessagingHandler::generateRandomString(5, true) . 'RID' . MessagingHandler::generateRandomString(5, true) . 'TS' . substr((string)microtime(), 2, 8); + } + + /** + * trimMessage + * + * @param String $header + * @param String $link + * @param String $body + * @param Int $length + * @return String + */ + private static function trimMessage(String $header, String $link, String $body, Int $length): String + { + if(strlen($header . $link) > $length) + { + return substr($header . $link, 0, $length); + } + $trimmed_body = substr($body, 0, $length - strlen($header . $link) - 4) . "... "; + return $header . $trimmed_body . $link; + } + + /** + * createPushNotificationFromNotification + * + * @param Int $recipientId + * @param Array $notification + * @param String $token + * @return Array + */ + private static function createPushNotificationFromNotification(Int $recipientId, Array $notification, String $token): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $webURL = Configure::read('App.weburl'); + $link = $webURL . $notification['link']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "PUSHNOTIFICATION" . $eventID; + $notificationEntity = TableRegistry::getTableLocator()->get('Notifications')->find()->where(['Notifications.user_id' => $recipientId])->order(['Notifications.created' => 'DESC'])->first(); + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => [ + 'token' => $token, + 'notification' => [ + 'title' => $notification['title'], + 'body' => $notification['body'], + ], + 'data' => [ + 'id' => !empty($notificationEntity->id) ? (string)$notificationEntity->id : '', + 'delay' => '', + 'start' => !empty($notification['start']) ? $notification['start'] : '', + 'datetime' => !empty($notification['datetime']) ? $notification['datetime'] : '', + 'before_link' => !empty($notification['before_link']) ? $notification['before_link'] : '', + 'link' => !empty($link) ? $link : '', + 'end' => !empty($notification['end']) ? $notification['end'] : '', + ], + ], + "RECIPIENTS" => [$token], + ]; + return $message; + } + + /** + * createSmsFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $number + * @return Array + */ + private static function createSmsFromNotification(String $recipientId, Array $notification, String $number): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "SMS" . $eventID . $number; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $notification_title = $notification['sms_skip_title'] ? '' : $notification['title'] . ': '; + $body = MessagingHandler::trimMessage($notification['start'] . $notification['datetime'] . ' ' . $notification_title, $notification['before_link'] . $link.$notification['end'], $notification['body'], 640); + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => substr($body, 0, 640), + "RECIPIENTS" => [$number], + "TYPE" => "INFOTIM", + "OSDC" => "DRPCSORIS", + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * createFaxFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $number + * @return Array + */ + private static function createFaxFromNotification(String $recipientId, Array $notification, String $number): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $subject = $notification['title']; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . ': ' . $notification['body'] . ' ' . $notification['before_link'] . $link . $notification['end']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "FAX" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => substr($body, 0, 640), + "SUBJECT" => $subject, + "RECIPIENTS" => [$number], + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * createEmailFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $email + * @return Array + */ + private static function createEmailFromNotification(String $recipientId, Array $notification, String $email): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $subject = $notification['datetime'] . ' ' . $notification['title']; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . ': ' . $notification['body'] . '.' . chr(0x0D) . $notification['before_link'] . $link.$notification['end'] . chr(0x0D) . chr(0x0D) . chr(0x0D) . '---' . chr(0x0D) . $notification['disclaimer']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "EMAIL" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => $body, + "SUBJECT" => $subject, + "RECIPIENTS" => [$email], + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * createTelegramChatMessageFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $telegram_chat_id + * @return Array + */ + private static function createTelegramChatMessageFromNotification(String $recipientId, Array $notification, String $telegram_chat_id): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = '🔔' . $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . '\n\n' . $notification['body'] . '. ' . $notification['before_link'] . '\n\n' . $link . "" . $notification['end']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "TELEGRAM" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => $body, + "RECIPIENTS" => [$telegram_chat_id], + ]; + return $message; + } + + /** + * createPecFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $pec + * @return Array + */ + private static function createPecFromNotification(String $recipientId, Array $notification, String $pec): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $subject = $notification['datetime'] . ' ' . $notification['title']; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . ': ' . $notification['body'] . '.' . chr(0x0D) . $notification['before_link'] . $link.$notification['end'] . chr(0x0D) . chr(0x0D) . chr(0x0D) . '---' . chr(0x0D) . $notification['disclaimer']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "PEC" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => $body, + "SUBJECT" => $subject, + "RECIPIENTS" => [$pec], + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * sendMessageToQueue + * + * @param Array $m + * @param String $queue + * @return void + */ + private static function sendMessageToQueue(Array $m, String $queue) + { + Log::write('debug', 'MessagingHandler::sendMessageToQueue publishing queue: ' . $queue); + Log::write('debug', 'MessagingHandler::sendMessageToQueue publishing message: ' . json_encode($m)); + $connection = new AMQPStreamConnection(Configure::read('App.rabbitMQhost'), Configure::read('App.rabbitMQport'), Configure::read('App.rabbitMQusername'), Configure::read('App.rabbitMQpassword')); + $channel = $connection->channel(); + $channel->queue_declare($queue, false, true, false, false); + $msg = new AMQPMessage(json_encode($m), ['delivery_mode' => 2]); + $channel->basic_publish($msg, '', $queue); + $channel->close(); + $connection->close(); + } + + /** + * sendMessageOfTypeToConfiguredProvider + * + * @param Array $message + * @param String $type + * @throws \Exception + * @return void + */ + private static function sendMessageOfTypeToConfiguredProvider(Array $message, String $type) + { + $dispatching_provider = Configure::read('App.messaging_config.' . $type); + Log::write('debug', "MessagingHandler::sendMessageToConfiguredProvider: $dispatching_provider"); + $queue = ''; + $m = []; + + switch ($dispatching_provider) { + case 'tim': + if ($type != 'sms') throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + $queue = Configure::read('App.messaging_broker_config.tim.sms.queue'); + $m["infotim"] = Configure::read('App.messaging_broker_config.tim.sms.infotim'); + $m["dispatching_method"] = 'tim'; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'firebase': + if ($type != 'push_notification') throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + $queue = Configure::read('App.messaging_broker_config.firebase.push_notification.queue'); + $m["dispatching_method"] = 'firebase'; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'amazon': + switch ($type) + { + case 'email': + $awsCredentials = [ + 'ses_aws_access_key_id' => Configure::read('App.messaging_broker_config.amazon.email.ses_aws_access_key_id'), + 'ses_aws_secret_access_key' => Configure::read('App.messaging_broker_config.amazon.email.ses_aws_secret_access_key'), + ]; + $queue = Configure::read('App.messaging_broker_config.amazon.email.queue'); + break; + + case 'sms': + $awsCredentials = [ + 'sns_aws_access_key_id' => Configure::read('App.messaging_broker_config.amazon.sms.sns_aws_access_key_id'), + 'sns_aws_secret_access_key' => Configure::read('App.messaging_broker_config.amazon.sms.sns_aws_secret_access_key'), + ]; + $queue = Configure::read('App.messaging_broker_config.amazon.sms.queue'); + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + } + $m["awsCredentials"] = $awsCredentials; + $m["dispatching_method"] = 'amazon'; + $m["messageChannel"] = ''; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'ies': + switch ($type) + { + case 'email': + $queue = Configure::read('App.messaging_broker_config.ies.email.queue'); + $m["smtp_username"] = Configure::read('App.messaging_broker_config.ies.email.smtp_username'); + $m["smtp_password"] = Configure::read('App.messaging_broker_config.ies.email.smtp_password'); + $m["default_sender"] = Configure::read('App.messaging_broker_config.ies.email.default_sender'); + $m["reply-to"] = Configure::read('App.messaging_broker_config.ies.email.reply-to'); + $m["list-unsubscribe"] = Configure::read('App.messaging_broker_config.ies.email.list-unsubscribe'); + $m["domain"] = Configure::read('App.messaging_broker_config.ies.email.domain'); + $m["messageChannel"] = Configure::read('App.messaging_broker_config.ies.email.messageChannel'); + break; + + case 'telegram': + $queue = Configure::read('App.messaging_broker_config.ies.telegram.queue'); + $m["telegram_bot_token"] = Configure::read('App.messaging_broker_config.ies.telegram.bot_token'); + break; + + case 'pec': + $queue = Configure::read('App.messaging_broker_config.ies.pec.queue'); + $m["smtp_username"] = Configure::read('App.messaging_broker_config.ies.pec.smtp_username'); + $m["smtp_password"] = Configure::read('App.messaging_broker_config.ies.pec.smtp_password'); + $m["default_sender"] = Configure::read('App.messaging_broker_config.ies.pec.default_sender'); + $m["reply-to"] = Configure::read('App.messaging_broker_config.ies.pec.reply-to'); + $m["list-unsubscribe"] = Configure::read('App.messaging_broker_config.ies.pec.list-unsubscribe'); + $m["domain"] = Configure::read('App.messaging_broker_config.ies.pec.domain'); + $m["messageChannel"] = Configure::read('App.messaging_broker_config.ies.pec.messageChannel'); + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + } + $m["dispatching_method"] = 'ies'; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'log': + switch ($type) + { + case 'fax': + $queue = Configure::read('App.messaging_broker_config.log.fax.queue'); + break; + + case 'email': + $queue = Configure::read('App.messaging_broker_config.log.email.queue'); + break; + + case 'sms': + $queue = Configure::read('App.messaging_broker_config.log.sms.queue'); + break; + + case 'telegram': + $queue = Configure::read('App.messaging_broker_config.log.telegram.queue'); + break; + + case 'push_notification': + $queue = Configure::read('App.messaging_broker_config.log.push_notification.queue'); + break; + + case 'pec': + $queue = Configure::read('App.messaging_broker_config.log.pec.queue'); + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + } + $m["dispatching_method"] = 'log'; + $m["messageChannel"] = 'log'; + $m["message"] = $message; + $m["type"] = $type; + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' not handled!"); + } + MessagingHandler::sendMessageToQueue($m, $queue); + } + + /** + * saveMessage + * + * @param Array $orig_message + * @param ?Int $user_id + * @param String $group + * @param Int $type_id + * @param ?Int $co_id + * @param ?Int $org_id + * @param String $contact + * @return void + */ + private static function saveMessage(Array $orig_message, ?Int $user_id, String $group, Int $type_id, ?Int $co_id, ?Int $org_id, String $contact) + { + $message = TableRegistry::getTableLocator()->get('Messages')->newEntity([ + 'controllable_object_id' => $co_id, + 'user_id' => $user_id, + 'organisation_id' => $org_id, + 'mgroup' => $group, + 'message_status_id' => 0, + 'content' => $orig_message['MESSAGE'], + 'event_string' => $orig_message['EVENT_ID'], + 'message_type_id' => $type_id, + 'last_update' => new DateTime(), + 'contact' => $contact, + ]); + + Log::write('debug', 'MessagingHandler::saveMessage saving messaage: ' . json_encode($message)); + if (!TableRegistry::getTableLocator()->get('Messages')->save($message)) { + Log::write('debug', 'MessagingHandler::saveMessage error:'); + Log::write('debug', json_encode($message->getErrors())); + } + } + + /** + * dispatch + * + * @param Array $recipients + * @param Array $notification + * @param String $group + * @param ?Int $co_id + * @param Int $dispatching_task_id + * @throws \Exception + * @return void + */ + public static function dispatch(Array $recipients, Array $notification, String $group, ?Int $co_id, Int $dispatching_task_id) + { + Log::write('debug', 'MessagingHandler::dispatch START'); + foreach($recipients as $recipient) + { + // inserisco nella notifica il datetime in base al timezone dello user. Se lo user non ha timezone + // o se si tratta di una organizzazione, usiamo il defaultUserTimezone: + $notification['datetime'] = (new DateTime())->i18nFormat(Configure::read('App.notification_datetime_format'), $recipient->timezone ?? Configure::read('App.defaultUserTimezone')); + + // recupero l'actor del recipient (che sia user o organisation): + $recipient_actor = $recipient->getActor(); + + // se l'actor non è ne USER ne ORGANISATION -> skip: + if (!in_array($recipient_actor->actor_type_id, [1, 5])) continue; + + // se il recipient è uno user e va usato otp per il tipo di notifica, + // genero otp, lo ingetto nella notifica, lo salvo nello user insieme a redirect url ed expires: + if ($recipient_actor->actor_type_id == 5 && $notification['use_otp']) { + $notification['otp'] = MessagingHandler::generateOneTimePassword(); + $recipient->otp = $notification['otp']; + $recipient->otp_redirect_url = empty($notification['link']) ? '/' : $notification['link']; + $hours = Configure::read('App.oneTimePasswordExpirationHours', 1); + $recipient->otp_expires = new DateTime("+$hours hours"); + TableRegistry::getTableLocator()->get('Users')->save($recipient); + } + + // stabilisco il prefix da inviare a createSmsFromNotification e createEmailFromNotification: + $recipientIdPrefix = $recipient_actor->actor_type_id == 1 ? 'O' : 'U'; + + // recupero il dispatching_task_item per l'actor specifico: + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->contain(['DispatchingTasks'])->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task_id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item) continue; + + if ($recipient_actor->actor_type_id == 5) { + // SOLO PER UTENTE - gestione invio PUSH NOTIFICATION: + $push_notification_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(0)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $push_notification_bit)) + { + foreach($recipient->getPushNotificationsWithNotifications() as $pushNotificationObj) + { + $pushNotification = $pushNotificationObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating PUSH NOTIFICATION for ' . $recipient->name . " " . $recipient->surname . " with token " . $pushNotification); + $message = MessagingHandler::createPushNotificationFromNotification($recipient->id, $notification, $pushNotification); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'push_notification'); + $message['MESSAGE'] = $message['MESSAGE']['notification']['title'] . ' - ' . $message['MESSAGE']['notification']['body']; + MessagingHandler::saveMessage($message, $recipient->id, $group, 0, $co_id, null, $pushNotification); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $push_notification_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + + // gestione invio SMS: + $sms_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(1)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $sms_bit)) + { + foreach($recipient->getMobilePhonesWithNotifications() as $mobileObj) + { + $mobile = $mobileObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating SMS for ' . $recipient_actor->description . " with number " . $mobile); + $message = MessagingHandler::createSmsFromNotification($recipientIdPrefix . $recipient->id . 'D' . $mobileObj->delivery_id, $notification, $mobile); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'sms'); + MessagingHandler::saveMessage($message, $recipient_actor->actor_type_id == 1 ? null : $recipient->id, $group, 1, $co_id, $recipient_actor->actor_type_id == 1 ? $recipient->id : null, $mobile); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $sms_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + + if ($recipient_actor->actor_type_id == 5) { + // SOLO PER UTENTE - gestione invio FAX: + $fax_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(2)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $fax_bit)) + { + foreach($recipient->getFaxesWithNotifications() as $faxObj) + { + $fax = $faxObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating FAX for ' . $recipient->name . " " . $recipient->surname . " with number " . $fax); + $message = MessagingHandler::createFaxFromNotification('U' . $recipient->id . 'D' . $faxObj->delivery_id, $notification, $fax); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'fax'); + MessagingHandler::saveMessage($message, $recipient->id, $group, 2, $co_id, null, $fax); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $fax_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + + // gestione invio EMAIL: + $email_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(3)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $email_bit)) + { + foreach($recipient->getEmailsWithNotifications() as $emailObj) + { + $email = $emailObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating EMAIL for ' . $recipient_actor->description . " with email " . $email); + $message = MessagingHandler::createEmailFromNotification($recipientIdPrefix . $recipient->id . 'D' . $emailObj->delivery_id, $notification, $email); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'email'); + MessagingHandler::saveMessage($message, $recipient_actor->actor_type_id == 1 ? null : $recipient->id, $group, 3, $co_id, $recipient_actor->actor_type_id == 1 ? $recipient->id : null, $email); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $email_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + + if ($recipient_actor->actor_type_id == 5) { + // SOLO PER UTENTE - gestione invio TELEGRAM CHAT (BOT): + $telegram_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(4)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $telegram_bit)) + { + foreach($recipient->getTelegramChatsWithNotifications() as $telegramChatObj) + { + $telegramChat = $telegramChatObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating TELEGRAM CHAT for ' . $recipient->name . " " . $recipient->surname . " with telegram_chat_id " . $telegramChat); + $message = MessagingHandler::createTelegramChatMessageFromNotification('U' . $recipient->id . 'D' . $telegramChatObj->delivery_id, $notification, $telegramChat); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'telegram'); + MessagingHandler::saveMessage($message, $recipient->id, $group, 4, $co_id, null, $telegramChat); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $telegram_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + + // gestione invio PEC: + $pec_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(5)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $pec_bit)) + { + foreach($recipient->getPecsWithNotifications() as $pecObj) + { + $pec = $pecObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating PEC for ' . $recipient_actor->description . " with PEC " . $pec); + $message = MessagingHandler::createPecFromNotification($recipientIdPrefix . $recipient->id . 'D' . $pecObj->delivery_id, $notification, $pec); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'pec'); + MessagingHandler::saveMessage($message, $recipient_actor->actor_type_id == 1 ? null : $recipient->id, $group, 5, $co_id, $recipient_actor->actor_type_id == 1 ? $recipient->id : null, $pec); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $pec_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + Log::write('debug', 'MessagingHandler::dispatch END'); + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php b/idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php new file mode 100644 index 0000000..fb49144 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php @@ -0,0 +1,169 @@ +get('NotificationTypes')->find()->where(['NotificationTypes.description' => $notification['type']])->first(); + $notification['type_id'] = $notificationType->id ?? ''; + } + + return $notification; + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php b/idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php new file mode 100644 index 0000000..90f6ac0 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php @@ -0,0 +1,243 @@ +channel(); + $channel->queue_declare(Configure::read('App.background_tasks.notifications.channel'), false, true, false, false); + $msg = new AMQPMessage(json_encode($m), ['delivery_mode' => 2]); + $channel->basic_publish($msg, '', Configure::read('App.background_tasks.notifications.channel')); + $channel->close(); + $connection->close(); + } + + /** + * dispatch + * + * @param Int|Null $co_id + * @param String $notification_code + * @param Array $options + * @param Int|String $group + * @param Int|Null $user_logged + * @return void + */ + public static function dispatch(Int|Null $co_id, String $notification_code, Array $options, String|Null $group = null, Int|Null $user_logged = null) + { + $group = !empty($group) ? $group : (new \DateTime())->format('ymdhi').substr((string)microtime(), 2, 8); + + $bt = TableRegistry::getTableLocator()->get('BackgroundTasks')->newEntity([ + 'command' => 'notifications_handler', + 'data' => json_encode(['co_id' => $co_id, 'notification_code' => $notification_code, 'options' => $options, 'group' => $group, 'user_logged' => $user_logged]), + 'dgroup' => $group, + ]); + if (TableRegistry::getTableLocator()->get('BackgroundTasks')->save($bt)) NotificationsHandler::sendDispatchingBackgroundTask(['command' => 'notifications_handler', 'data' => json_encode(['background_task_id' => $bt->id])]); + } + + /** + * executeDispatch + * + * @param Int|Null $co_id + * @param String $notification_code + * @param Array $options + * @param String $group + * @param Int|Null $user_logged + * @throws \Exception + * @return void + */ + public static function executeDispatch(Int|Null $co_id, String $notification_code, Array $options, String $group, Int|Null $user_logged) + { + Log::write('debug', 'NotificationsHandler::executeDispatch - DISPATCH FOR CODE: "' . $notification_code . '" AND GROUP: "' . $group . '" START!!!'); + + $dispatch_step = 0; + + // Fase 0 (eseguita sempre) - creazione/aggiornamento task: + $background_task = TableRegistry::getTableLocator()->get('BackgroundTasks')->find()->where(['BackgroundTasks.dgroup' => $group])->first(); + if ($background_task) { + Log::write('debug', 'NotificationsHandler::executeDispatch - linked background_task id: ' . $background_task->id); + $dispatching_task = TableRegistry::getTableLocator()->get('DispatchingTasks')->find()->where(['DispatchingTasks.background_task_id' => $background_task->id])->first(); + if (!$dispatching_task) { + Log::write('debug', 'NotificationsHandler::executeDispatch - Creating new dispatching_task'); + $dispatching_task = TableRegistry::getTableLocator()->get('DispatchingTasks')->newEntity([ + 'dispatching_task_group' => $group, + 'dispatching_task_status_id' => 1, + 'retries' => 0, + 'failed' => false, + 'background_task_id' => $background_task->id, + ]); + } else { + if ($dispatching_task->dispatching_task_status_id != 5 && !$dispatching_task->failed) $dispatching_task->retries++; + } + if ($dispatching_task->dispatching_task_status_id != 5 && !$dispatching_task->failed) { + if ($dispatching_task->retries >= Configure::read('App.dispatching_task_max_retries')) $dispatching_task->failed = true; + Log::write('debug', 'NotificationsHandler::executeDispatch - Saving dispatching_task:' . json_encode($dispatching_task)); + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->failed ? 0 : $dispatching_task->dispatching_task_status_id; + } + } + + // Fase 1 - Retrieving - se lo stato è "recipients_detection": + if ($dispatch_step == 1) { + Log::write('debug', 'NotificationsHandler::executeDispatch - RECIPIENTS_DETECTION START!!!'); + $recipients = RecipientsDetector::getRecipients($notification_code, $options); + + // in questo foreach prendo un utente e verifico se ha almeno un recapito valido: + // si: rimuovo l'organizzazione da recipients, almeno c'è un destinatario in grado di ricevere, quindi l'org va rimossa. + // no: vado avanti (l'organizzazione rimane dentro recipients e quindi verrà lasciata, se poi dopo si trova un utente che ha recapiti in caso viene rimossa) + if (count($recipients['users']) > 0) Log::write('debug', 'NotificationsHandler::executeDispatch - checking users to be notified (if they have notification enabled push notifications, mobile phones, faxes, emails, telegram chats or PECs):'); + foreach ($recipients['users'] as $recipient) { + // creo (se non esiste il task item per l'utente specifico): + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item) { + Log::write('debug', 'NotificationsHandler::executeDispatch - creating dispatching_task_item for user recipient with id: ' . $recipient->id); + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->newEntity([ + 'dispatching_task_id' => $dispatching_task->id, + 'actor_id' => $recipient->actor_id, + 'system_dispatched' => false, + 'actor_dispatching_bitmask' => $recipient->getDispatchingBitmask($notification_code), + 'performed_dispatching_bitmask' => 0, + ]); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + if($notification_code != 'test_all' && isset($recipient->organisation_id) && $recipient->getDispatchingBitmask($notification_code) > 0) + { + if (($key = array_search($recipient->organisation_id, $recipients['organisations'])) !== false) { + Log::write('debug', 'NotificationsHandler::executeDispatch - Removing organisation with ID: ' . $recipients['organisations'][$key] . ' from notifiable organisations because there is at least 1 belonging user that will be notified!'); + unset($recipients['organisations'][$key]); + } + } + } + + if (count($recipients['organisations']) > 0) Log::write('debug', 'NotificationsHandler::executeDispatch - checking organisations to be notified (if they have notification enabled mobile phones, emails or PECs):'); + foreach($recipients['organisations'] as $organisation_id) + { + $recipient = TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $organisation_id])->first(); + if (!$recipient) continue; + + // creo (se non esiste il task item per l'org specifica): + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item && $recipient->getDispatchingBitmask()) { + Log::write('debug', 'NotificationsHandler::executeDispatch - creating dispatching_task_item for organisation recipient with id: ' . $recipient->id); + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->newEntity([ + 'dispatching_task_id' => $dispatching_task->id, + 'actor_id' => $recipient->actor_id, + 'system_dispatched' => null, + 'actor_dispatching_bitmask' => $recipient->getDispatchingBitmask(), + 'performed_dispatching_bitmask' => 0, + ]); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - RECIPIENTS_DETECTION END!!!'); + } + + $notification = null; + if (in_array($dispatch_step, [2,3,4])) { + $notification = NotificationGenerator::getNotification($co_id, $notification_code, $options); + $notification['user_logged'] = $user_logged; + Log::write('debug', 'NotificationsHandler::executeDispatch - GENERATED NOTIFICATION: ' . json_encode($notification)); + } + + // Fase 2 - se lo stato è "system_dispatching": + if ($dispatch_step == 2) { + Log::write('debug', 'NotificationsHandler::executeDispatch - SYSTEM_DISPATCHING START!!!'); + + $actor_ids_query = TableRegistry::getTableLocator()->get('DispatchingTaskItems') + ->find() + ->select(['DispatchingTaskItems.actor_id']) + ->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.system_dispatched' => false]); + + $users = TableRegistry::getTableLocator()->get('Users') + ->find() + ->where(['Users.actor_id IN' => $actor_ids_query]) + ->toArray(); + + if($notification_code != "password_recovery" && $notification_code != "verify-citizen-registration") + { + SystemNotificationsDispatcher::dispatch($users, $notification, $group, $co_id, $dispatching_task->id); + } + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - SYSTEM_DISPATCHING END!!!'); + } + + // Fase 3 - se lo stato è "users_message_dispatching": + if ($dispatch_step == 3) { + Log::write('debug', 'NotificationsHandler::executeDispatch - USERS_MESSAGE_DISPATCHING START!!!'); + + $actor_ids_query = TableRegistry::getTableLocator()->get('DispatchingTaskItems') + ->find() + ->select(['DispatchingTaskItems.actor_id']) + ->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.system_dispatched IS NOT NULL', 'DispatchingTaskItems.not_performed_dispatching_bitmask > 0']); + + $users = TableRegistry::getTableLocator()->get('Users') + ->find() + ->where(['Users.actor_id IN' => $actor_ids_query]) + ->toArray(); + + MessagingHandler::dispatch($users, $notification, $group, $co_id, $dispatching_task->id); + + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - USERS_MESSAGE_DISPATCHING END!!!'); + } + + // Fase 4 - se lo stato è "organisations_message_dispatching": + if ($dispatch_step == 4) { + Log::write('debug', 'NotificationsHandler::executeDispatch - ORGANISATIONS_MESSAGE_DISPATCHING START!!!'); + + $actor_ids_query = TableRegistry::getTableLocator()->get('DispatchingTaskItems') + ->find() + ->select(['DispatchingTaskItems.actor_id']) + ->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.system_dispatched IS NULL', 'DispatchingTaskItems.not_performed_dispatching_bitmask > 0']); + + $organisations = TableRegistry::getTableLocator()->get('Organisations') + ->find() + ->where(['Organisations.actor_id IN' => $actor_ids_query]) + ->toArray(); + + MessagingHandler::dispatch($organisations, $notification, $group, $co_id, $dispatching_task->id); + + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - ORGANISATIONS_MESSAGE_DISPATCHING END!!!'); + } + Log::write('debug', 'NotificationsHandler::executeDispatch - DISPATCH FOR CODE: "' . $notification_code . '" AND GROUP: "' . $group . '" END!!!'); + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php b/idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php new file mode 100644 index 0000000..94ed81f --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php @@ -0,0 +1,119 @@ + [], 'organisations' => []]; + + switch($notification_code) + { + case "test_all": + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->toArray(); + $recipients['organisations'] = TableRegistry::getTableLocator()->get('Organisations')->find()->all()->extract('id')->toArray(); + break; + case "verify-citizen-registration": + case "password_recovery": + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['user_id']); + break; + + case "send_to_drar_admin": + // recupero gli utenti appartenenti all'organizzazione di tipo DRAR (id 6) + // che hanno la capability "documentation.water_drawing_paperworks.assign": + $user_ids_query = TableRegistry::getTableLocator()->get('Users') + ->find() + ->matching('Groups.Capabilities') + ->matching('Organisations') + ->select(['Users.id']) + ->where(['Organisations.organisation_type_id' => 6, 'Capabilities.value' => 'documentation.water_drawing_paperworks.assign']); + + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id IN' => $user_ids_query])->toArray(); + break; + case "send_to_drar_anac_user": + // recupero gli utenti appartenenti all'organizzazione di tipo DRAR (id 6) + // che hanno la capability "documentation.water_drawing_paperworks.antimafia_request": + $user_ids_query = TableRegistry::getTableLocator()->get('Users') + ->find() + ->matching('Groups.Capabilities') + ->matching('Organisations') + ->select(['Users.id']) + ->where(['Organisations.organisation_type_id' => 6, 'Capabilities.value' => 'documentation.water_drawing_paperworks.antimafia_request']); + + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id IN' => $user_ids_query])->toArray(); + break; + case "send_to_drar_user_antimafia_uploaded": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['drar_user_id']); + break; + case "send_to_drar_user_antimafia_request_expired": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['drar_user_id']); + break; + case "send_to_drar_user": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['drar_user_id']); + break; + case "send_to_gc_user": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_user_paperwork_verified": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_user_request_self_certification": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_user_paperwork_completed": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_assign_paperwork": + // recupero gli utenti appartenenti all'organizzazione di tipo GC (id 0) + // che hanno la capability "documentation.water_drawing_paperworks.assign": + $user_ids_query = TableRegistry::getTableLocator()->get('Users') + ->find() + ->matching('Groups.Capabilities') + ->matching('Organisations') + ->select(['Users.id']) + ->where(['Organisations.province' => $options['water_drawing_paperwork_province'], 'Organisations.organisation_type_id' => 0, 'Capabilities.value' => 'documentation.water_drawing_paperworks.assign']); + + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id IN' => $user_ids_query])->toArray(); + + // recupero l'organizzazione di tipo GC (id 0) per la provincia di competenza: + $recipients['organisations'] = TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.organisation_type_id' => 0, 'Organisations.province' => $options['water_drawing_paperwork_province']])->all()->extract('id')->toArray(); + break; + case "send_to_gc_validate_paperwork": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_citizen_paperwork_verified": + // recupero l'utente Cittadino a cui la pratica risulta intestata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.tax_code' => $options['citizen_user_tax_code']])->first(); + break; + case "send_result_of_validation_to_operator": + // recupero l'utente Cittadino a cui la pratica risulta intestata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id' => $options['user_id']])->first(); + break; + case "send_to_last_edit_user_intended_use_check_completed": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['last_edit_user_id']); + break; + default: + break; + } + return $recipients; + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php b/idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php new file mode 100644 index 0000000..ab1c948 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php @@ -0,0 +1,122 @@ +get('Notifications')->newEntity([ + 'user_id' => $user_id, + 'notification_type_id' => $orig_notification['type_id'], + 'thread' => substr($type_string, 0, 45 - strlen($co_id_string) - 1) . '-' . $co_id_string, + 'info' => json_encode($orig_notification), + 'ngroup' => $group, + 'controllable_object_id' => $co_id, + ]); + + Log::write('debug', 'SystemNotificationsDispatcher::saveNotification saving notification: ' . json_encode($notification)); + if (!TableRegistry::getTableLocator()->get('Notifications')->save($notification)) { + Log::write('debug', 'SystemNotificationsDispatcher::saveNotification error:'); + Log::write('debug', json_encode($notification->getErrors())); + return null; + } + return $notification->id; + } + + /** + * createSystemNotificationFromNotification + * + * @param Int $user_id + * @param Array $orig_notification + * @param Int $saved_notification_id + * @return Object + */ + private static function createSystemNotificationFromNotification(Int $user_id, Array $orig_notification, Int $saved_notification_id): Object + { + $system_notification = (object)[]; + $system_notification->type = "notification"; + $system_notification->user_ids = [$user_id]; + $system_notification->notification_ids = [$user_id => $saved_notification_id]; + $system_notification->msg = (object)[]; + $system_notification->msg->title = $orig_notification['title']; + $system_notification->msg->body = $orig_notification['body']; + $system_notification->msg->type = TableRegistry::getTableLocator()->get('NotificationTypes')->find()->where(['NotificationTypes.id' => $orig_notification['type_id'] ?? 0])->first()->description ?? 'unknown'; + $system_notification->msg->sound = 'notification'; + return $system_notification; + } + + /** + * sendNotification + * + * @param Object $system_notification + * @return void + */ + private static function sendNotification(Object $system_notification) + { + Log::write('debug', 'SystemNotificationsDispatcher::sendNotificationRequests publishing exchange: ' . Configure::read('App.notificatorExchange')); + Log::write('debug', 'SystemNotificationsDispatcher::sendNotificationRequests publishing system_notification: ' . json_encode($system_notification)); + $connection = new AMQPStreamConnection(Configure::read('App.rabbitMQhost'), Configure::read('App.rabbitMQport'), Configure::read('App.rabbitMQusername'), Configure::read('App.rabbitMQpassword')); + $channel = $connection->channel(); + $exchange = Configure::read('App.notificatorExchange'); + $channel->exchange_declare($exchange, 'fanout', false, true, false); + $msg = new AMQPMessage(json_encode($system_notification), ['expiration' => '600000']); + $channel->basic_publish($msg, $exchange); + $channel->close(); + $connection->close(); + } + + /** + * dispatch + * + * @param Array $recipients + * @param Array $orig_notification + * @param String $group + * @param ?Int $co_id + * @param Int $dispatching_task_id + * @throws \Exception + * @return void + */ + public static function dispatch(Array $recipients, Array $orig_notification, String $group, ?Int $co_id, Int $dispatching_task_id) + { + Log::write('debug', 'SystemNotificationsDispatcher::dispatch START'); + foreach($recipients as $recipient) + { + // recupero il dispatching_task_item per l'actor specifico: + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->contain(['DispatchingTasks'])->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task_id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item) continue; + + $saved_notification_id = SystemNotificationsDispatcher::saveNotification($orig_notification, $recipient->id, $group, $co_id); + if (!is_int($saved_notification_id)) continue; + $system_notification = SystemNotificationsDispatcher::createSystemNotificationFromNotification($recipient->id, $orig_notification, $saved_notification_id); + SystemNotificationsDispatcher::sendNotification($system_notification); + + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->system_dispatched = true; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + Log::write('debug', 'SystemNotificationsDispatcher::dispatch END'); + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php b/idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php new file mode 100644 index 0000000..c12ae88 --- /dev/null +++ b/idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php @@ -0,0 +1,304 @@ +get('ControllableObjects')->find()->contain(['ControllableObjectTypes'])->where(['ControllableObjects.id' => $controllable_object_id])->first(); + if (!isset($controllable_object->controllable_object_type->description)) return false; + + switch($controllable_object->controllable_object_type->description) + { + case "water_drawing_paperwork": + $snapshot = SnapshotsHandler::createSnapshotForWaterDrawingPaperworks($controllable_object_id); + break; + } + + if (!isset($snapshot)) return false; + + $user_id = Router::getRequest()?->getAttribute('identity')?->id; + $controller = Router::getRequest()?->getParam('controller'); + $action = Router::getRequest()?->getParam('action'); + + if (!isset($user_id) || !isset($controller) || !isset($action)) return false; + + $snapshotsTable = TableRegistry::getTableLocator()->get('Snapshots'); + $snapshotEntity = $snapshotsTable->newEntity([ + 'controllable_object_type_id' => $controllable_object->controllable_object_type_id, + 'controllable_object_id' => $controllable_object_id, + 'object_snapshot' => $snapshot, + 'date' => new DateTime(), + 'user_id' => $user_id, + 'controller_action' => "$controller-$action", + ]); + if (!$snapshotsTable->save($snapshotEntity)) return false; + + // all good! + return true; + } + + /** + * createSnapshotForWaterDrawingPaperworks + * + * @param Int $controllable_object_id + * @return String + */ + private static function createSnapshotForWaterDrawingPaperworks(Int $controllable_object_id): String + { + $controllableObjectsTable = TableRegistry::getTableLocator()->get('ControllableObjects'); + $contain = [ + 'Organisations' => [ + 'Actors', + ], + 'Locations', + 'ChildAttachments' => [ + 'Tags', + 'ControllableObjects' => [ + 'Locations', + 'Creator' => [ + 'Organisations' => [ + 'Actors' + ] + ] + ] + ], + 'Creator' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'Modifier' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'WaterDrawingPaperworks' => [ + 'WaterDrawingPaperworkPecs' => [ + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + 'WaterDrawingPaperworkStatuses', + 'WaterDrawingArticles', + 'DrarUsers' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'GcUsers' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => [ + 'WaterDrawingAntimafiaCertificationRequestStatuses', + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + 'WaterDrawingFees' => [ + 'WaterDrawingPayments' => [ + 'WaterDrawingPaymentTypes', + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + ], + 'WaterDrawingPaperworkHistories' => [ + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + 'WaterDrawingDerivations' => [ + 'WaterDrawingDerivationTypes', + ], + 'WaterDrawingReturnPoints', + 'WaterDrawingIntendedUses' => [ + 'WaterDrawingIntendedUseTypes', + 'CadastralCropTypes', + 'WaterDrawingMeters' => [ + 'WaterDrawingToolTypes', + 'WaterDrawingMeasurements' => [ + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + ], + ], + ], + ]; + + $logged_user = Router::getRequest()?->getAttribute('identity'); + + // disabilitiamo temporaneamente lo UserTimezoneDatetimeEntityTrait altrimenti la serializzazione + // verrà eseguita con tutte le date nel timezone dello user loggato e non in UTC!!!!!> + if ($logged_user) $logged_user->disableUserTimezoneDatetimeEntityTrait = true; + + $waterDrawingPaperwork = $controllableObjectsTable->find()->contain($contain)->where(['ControllableObjects.id' => $controllable_object_id])->first(); + + // riabilitiamo lo UserTimezoneDatetimeEntityTrait post serializzazione + if ($logged_user) $logged_user->disableUserTimezoneDatetimeEntityTrait = false; + + return base64_encode(serialize($waterDrawingPaperwork)); + } + + /** + * getControllableObjectFromSnapshotWithId + * + * @param Int $snapshot_id + * @return ControllableObject|Null + */ + public static function getControllableObjectFromSnapshotWithId(Int $snapshot_id): ?ControllableObject + { + $snapshotsTable = TableRegistry::getTableLocator()->get('Snapshots'); + $snapshot = $snapshotsTable->find()->where(['Snapshots.id' => $snapshot_id])->first(); + if (!$snapshot) return null; + return unserialize(base64_decode($snapshot->object_snapshot)); + } + + /** + * getLastWaterDrawingPaperworkUnpackingVersion + * + * @return Int + */ + public static function getLastWaterDrawingPaperworkUnpackingVersion(): Int + { + // ogni volta che si modifica il codice del metodo seguente getUnpackedWaterDrawingPaperworkSnapshot(), + // incrementare il numero int da restituire. Questo permetterà al cron job di rieseguire l'unpacking + // secondo la nuova versione. + return 1; + } + + /** + * getSnapshotControllerActionDescription + * + * @param String $controller_action + * @return String + */ + public static function getSnapshotControllerActionDescription($controller_action): String + { + $controller_action_descriptions = [ + 'WaterDrawingPaperworks-add' => __('ha creato una nuova Pratica di Attingimento'), + 'WaterDrawingPaperworks-add_scan' => __('ha inserito una nuova Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-edit' => __('ha modificato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-edit_scan' => __('ha modificato la Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-delete' => __('ha eliminato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-validate_scan' => __('ha verificato la Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-upload_attachment' => __('ha inserito un allegato sulla Pratica di Attingimento'), + 'WaterDrawingPaperworks-upload_attachment_scan' => __('ha inserito un allegato sulla Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-send_to_validation' => __('ha inviato in validazione la Pratica di Attingimento'), + 'WaterDrawingPaperworks-assign' => __('ha assegnato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-validate' => __('ha verificato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-send_to_drar' => __('ha inviato la Pratica di Attingimento al DRAR'), + 'WaterDrawingPaperworks-send_to_gc' => __('ha inviato la Pratica di Attingimento al Genio Civile'), + 'WaterDrawingPaperworks-submit_antimafia_request' => __('ha creato la richiesta Antimafia'), + 'WaterDrawingPaperworks-antimafia_request_to_anac' => __('ha inviato la richiesta Antimafia all\'ANAC'), + 'WaterDrawingPaperworks-request_self_certification' => __('ha richiesto l\'autocertificazione Antimafia'), + 'WaterDrawingPaperworks-upload_antimafia_attachment' => __('ha inserito l\'allegato Antimafia'), + 'WaterDrawingPayments-add' => __('ha inserito un pagamento sulla Pratica di Attingimento'), + 'WaterDrawingPayments-edit' => __('ha aggiornato un pagamento sulla Pratica di Attingimento'), + 'WaterDrawingPayments-delete' => __('ha cancellato un pagamento sulla Pratica di Attingimento'), + 'WaterDrawingPaperworkPecs-add' => __('ha inserito un documento PEC sulla Pratica di Attingimento'), + 'WaterDrawingPaperworkPecs-edit' => __('ha aggiornato un documento PEC sulla Pratica di Attingimento'), + 'WaterDrawingPaperworkPecs-delete' => __('ha cancellato un documento PEC sulla Pratica di Attingimento'), + 'WaterDrawingDerivations-add' => __('ha inserito un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-edit' => __('ha aggiornato un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-delete' => __('ha cancellato un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-update_location' => __('ha aggiornato la località di un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-update_data' => __('ha aggiornato la portata e il volume di un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingFees-add' => __('ha inserito un canone alla Pratica di Attingimento'), + 'WaterDrawingFees-edit' => __('ha aggiornato un canone alla Pratica di Attingimento'), + 'WaterDrawingFees-delete' => __('ha cancellato un canone alla Pratica di Attingimento'), + 'WaterDrawingMeters-add' => __('ha inserito uno strumento di misura alla Pratica di Attingimento'), + 'WaterDrawingMeters-edit' => __('ha aggiornato un strumento di misura alla Pratica di Attingimento'), + 'WaterDrawingMeters-delete' => __('ha cancellato un strumento di misura alla Pratica di Attingimento'), + 'WaterDrawingMeasurements-add' => __('ha inserito una misurazione alla Pratica di Attingimento'), + 'WaterDrawingMeasurements-delete' => __('ha cancellato una misurazione alla Pratica di Attingimento'), + 'WaterDrawingReturnPoints-add' => __('ha inserito un punto di restituzione alla Pratica di Attingimento'), + 'WaterDrawingReturnPoints-edit' => __('ha aggiornato un punto di restituzione alla Pratica di Attingimento'), + 'WaterDrawingReturnPoints-delete' => __('ha cancellato un punto di restituzione alla Pratica di Attingimento'), + ]; + return $controller_action_descriptions[$controller_action] ?? ''; + } + + /** + * getUnpackedWaterDrawingPaperworkSnapshot + * + * @param Int $snapshot_id + * @return UnpackedWaterDrawingPaperworkSnapshot!Null + */ + public static function getUnpackedWaterDrawingPaperworkSnapshot(Int $snapshot_id): ?UnpackedWaterDrawingPaperworkSnapshot + { + $co = SnapshotsHandler::getControllableObjectFromSnapshotWithId($snapshot_id); + if (!$co) return null; + + $snapshot = TableRegistry::getTableLocator()->get('Snapshots') + ->find() + ->contain(['Users' => ['Actors', 'Organisations' => ['Actors']]]) + ->where(['Snapshots.id' => $snapshot_id]) + ->first(); + + if (!$snapshot) return null; + + $unpacked_water_drawing_paperwork_snapshot = []; + + // Inizializzazione valori di base: + $unpacked_water_drawing_paperwork_snapshot['snapshot_id'] = $snapshot_id; + $unpacked_water_drawing_paperwork_snapshot['unpacking_version'] = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpacked_water_drawing_paperwork_snapshot['who'] = $snapshot->user?->name. ' ' . $snapshot->user?->surname; + $unpacked_water_drawing_paperwork_snapshot['when'] = isset($snapshot->date) ? new DateTime($snapshot->date->format("Y-m-d H:i:s")) : null; + $unpacked_water_drawing_paperwork_snapshot['what'] = SnapshotsHandler::getSnapshotControllerActionDescription($snapshot->controller_action); + + // Inizializzazione valori presi da oggetto 'root' (controllable_object): + $creator_organisation = isset($co->creator->organisation->actor->description) ? " (" . $co->creator->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['creator'] = $co->creator->name . ' ' . $co->creator->surname . $creator_organisation; + $unpacked_water_drawing_paperwork_snapshot['created'] = isset($co->created) ? new DateTime($co->created->format("Y-m-d H:i:s")) : null; + $modifier_organisation = isset($co->modifier->organisation->actor->description) ? " (" . $co->modifier->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['modifier'] = $co->modifier->name . ' ' . $co->modifier->surname . $modifier_organisation; + $unpacked_water_drawing_paperwork_snapshot['modified'] = isset($co->modified) ? new DateTime($co->modified->format("Y-m-d H:i:s")) : null; + + // Inizializzazione valori presi da specializzazione oggetto (water_drawing_paperwork): + $unpacked_water_drawing_paperwork_snapshot['water_drawing_paperwork_id'] = $co->water_drawing_paperwork->id; + $unpacked_water_drawing_paperwork_snapshot['water_drawing_paperwork_status'] = $co->water_drawing_paperwork->water_drawing_paperwork_status->description; + $gc_user_organisation = isset($co->water_drawing_paperwork->gc_user->organisation->actor->description) ? " (" . $co->water_drawing_paperwork->gc_user->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['gc_user'] = $co->water_drawing_paperwork->gc_user?->name . ' ' . $co->water_drawing_paperwork->gc_user?->surname . $gc_user_organisation; + $drar_user_organisation = isset($co->water_drawing_paperwork->drar_user->organisation->actor->description) ? " (" . $co->water_drawing_paperwork->drar_user->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['drar_user'] = $co->water_drawing_paperwork->drar_user?->name . ' ' . $co->water_drawing_paperwork->drar_user?->surname . $drar_user_organisation; + + return TableRegistry::getTableLocator()->get('UnpackedWaterDrawingPaperworkSnapshots')->newEntity($unpacked_water_drawing_paperwork_snapshot); + } +} diff --git a/idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php new file mode 100644 index 0000000..6efd1d8 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php @@ -0,0 +1,27 @@ + 1 ? strtolower($file_name_parts[count($file_name_parts) - 1]) : ''; + // if (!in_array($file_name_extension, ["txt", "pdf", "jpg", "png"])) throw new \Exception(__('Allegato "{0}" non valido! Estensione file "{1}" non ammessa!', $attachment['name'], $file_name_extension)); + // if (!in_array(mime_content_type($attachment['tmp_name']), ["text/plain", "application/pdf", "image/jpeg", "image/png"])) throw new \Exception(__('Allegato "{0}" non ammesso! Tipo dichiarato: "{1}", tipo realmente riscontrato: "{2}". Dimensioni: "{3} bytes"', $attachment['name'], $attachment['type'], mime_content_type($attachment['tmp_name']), $attachment['size'])); + } else { + if (!$skip_form_check) throw new \Exception(__('L\'allegato "{0}" non risulta caricato correttamente tramite apposita funzione nel form!', $attachment['name'])); + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php new file mode 100644 index 0000000..5553c13 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php @@ -0,0 +1,39 @@ +getError() === 0) { + return [ + 'name' => $attachment->getClientFilename(), + 'size' => $attachment->getSize(), + 'tmp_name' => $attachment->getStream()->getMetadata('uri'), + 'type' => $attachment->getClientMediaType(), + 'error' => $attachment->getError(), + ]; + } else { + return [ + 'name' => '', + 'size' => '', + 'tmp_name' => '', + 'type' => '', + 'error' => $attachment->getError(), + ]; + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php b/idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php new file mode 100644 index 0000000..4d03d42 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php @@ -0,0 +1,133 @@ + il path del file firmato da controllare + * $signer_fiscal_code -----------------------------------> il CF che dovrebbe essere presente nella firma (dentro il certificato) + * $signer_description -----------------------------------> descrizione del firmatario in base al contesto + * $certificate_expired_if_expires_within_seconds -> il lasso di tempo espresso in secondi entro il quale + * il certificato DEVE essere ancora valido per non considerarlo SCADUTO + * valore di default 1 ora (86400 seconds) + * + * @param String $signed_attachment + * @param String $signer_fiscal_code + * @param String $signer_description + * @param String $certificate_expired_if_expires_within_seconds + * @return Bool|String + */ + public static function check_cades(String $signed_attachment, String $signer_fiscal_code, String $signer_description, String $certificate_expired_if_expires_within_seconds = '86400'): Bool|String + { + $command = null; + $output = null; + $result_code = null; + + // Verifica formale firma: + $tmpfname = tempnam(sys_get_temp_dir(), 'signed_file_content_'); + $command = "openssl cms -verify -noverify -in $signed_attachment -inform DER -out $tmpfname"; + exec($command, $output, $result_code); + unlink($tmpfname); + unset($output); + if ($result_code) return __('Verifica formale della firma fallita!'); + + // Estrazione del certificato PEM allegato al file firmato: + $signed_file_certificate = tempnam(sys_get_temp_dir(), 'signed_file_certificate_'); + $command = "openssl pkcs7 -inform DER -in $signed_attachment -print_certs -out $signed_file_certificate"; + exec($command, $output, $result_code); + unset($output); + if ($result_code) { + unlink($signed_file_certificate); + return __('Impossibile estrarre il certificato dal file firmato!'); + } + + // Verifica formale del certificato PEM estratto: + $command = "openssl x509 -in $signed_file_certificate -noout"; + exec($command, $output, $result_code); + unset($output); + if ($result_code) { + unlink($signed_file_certificate); + return __('Certificato formalmente non valido!'); + } + + // Verifica se il certificato PEM estratto scadrà entro i prossimi "$certificate_expired_if_expires_within_seconds" secondi: + $command = "openssl x509 -in $signed_file_certificate -noout -checkend $certificate_expired_if_expires_within_seconds"; + exec($command, $output, $result_code); + unset($output); + if ($result_code) { + unlink($signed_file_certificate); + $hours = $certificate_expired_if_expires_within_seconds / 3600; + return __("Certificato scaduto o in scadenza nelle prossime $hours ore!"); + } + + // Verifica formale del certificato PEM estratto ed estrazione attributi del firmatario (ultimo subject nella chain!): + $command = "awk 'BEGIN {c=0; out=\"\"} /BEGIN CERTIFICATE/ {c++; out=\"\";} {out = out \$0 ORS} /END CERTIFICATE/ {last=out;} END {print last}' $signed_file_certificate | openssl x509 -noout -subject"; + exec($command, $output, $result_code); + if ($result_code) { + unlink($signed_file_certificate); + return __('Errore durante l\'estrazione delle informazioni del soggetto firmatario dal certificato!'); + } + + // Estrazione del CODICE FISCALE dal certificato PEM estratto: + $certificate_fiscal_code = self::extract_fiscal_code_from_certificate_subject_row($output[0]); + if (!$certificate_fiscal_code) { + unlink($signed_file_certificate); + return __('Errore durante l\'estrazione del Codice Fiscale dal certificato!'); + } + + // Controlliamo se il CODICE FISCALE preso dal certificato PEM estratto coincide con quello passato: + if ($certificate_fiscal_code != $signer_fiscal_code) { + unlink($signed_file_certificate); + return __("Il Codice Fiscale del firmatario del documento non corrisponde a quello del $signer_description!"); + } + + // Tutto OK! + unlink($signed_file_certificate); + return true; + } + + /** + * extract_certificate_subject_fiscal_code + * + * @param String $certificate_attributes + * @return ?String + */ + private static function extract_fiscal_code_from_certificate_subject_row(String $certificate_subject_row): ?String { + // estrazione CF con subject preceduto da "TINIT-": + $serial_number_start_index = strpos($certificate_subject_row, "TINIT-"); + if ($serial_number_start_index !== false) return substr($certificate_subject_row, $serial_number_start_index + 6, 16); + // estrazione CF con subject preceduto da "CN=": + $serial_number_start_index = strpos($certificate_subject_row, "CN="); + if ($serial_number_start_index !== false) return substr($certificate_subject_row, $serial_number_start_index + 3, 16); + return null; + } + + /** + * check_pades + * + * controlla la firma di un file in formato PAdES + * + * $signed_attachment -----------------------------> il path del file firmato da controllare + * $signer_fiscal_code -----------------------------------> il CF che dovrebbe essere presente nella firma (dentro il certificato) + * $signer_description -----------------------------------> descrizione del firmatario in base al contesto + * $certificate_expired_if_expires_within_seconds -> il lasso di tempo espresso in secondi entro il quale + * il certificato DEVE essere ancora valido per non considerarlo SCADUTO + * valore di default 1 ora (86400 seconds) + * + * @param mixed $signed_attachment + * @param mixed $signer_fiscal_code + * @param String $signer_description + * @param mixed $certificate_expired_if_expires_within_seconds + * @return Bool|String + */ + public static function check_pades(String $signed_attachment, String $signer_fiscal_code, String $signer_description, String $certificate_expired_if_expires_within_seconds = '86400'): Bool|String + { + return true; + } +} diff --git a/idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php b/idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php new file mode 100644 index 0000000..7c6c5f5 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php @@ -0,0 +1,25 @@ +showAlert; + } + + public function setShowAlert(bool $showAlert): CitizenRegistrationDTO + { + $this->showAlert = $showAlert; + return $this; + } + + public function getFiscalCode(): string + { + return $this->fiscalCode; + } + + public function setFiscalCode(string $fiscalCode): CitizenRegistrationDTO + { + $this->fiscalCode = $fiscalCode; + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): CitizenRegistrationDTO + { + $this->name = $name; + return $this; + } + + public function getSurname(): string + { + return $this->surname; + } + + public function setSurname(string $surname): CitizenRegistrationDTO + { + $this->surname = $surname; + return $this; + } + + public function getGender(): string + { + return $this->gender; + } + + public function setGender(string $gender): CitizenRegistrationDTO + { + $this->gender = $gender; + return $this; + } + + public function getBirthdate(): string + { + return !empty($this->birthdate) ? new DateTime($this->birthdate)->format('Y-m-d') : ''; + } + + public function setBirthdate(string $birthdate): CitizenRegistrationDTO + { + $this->birthdate = $birthdate; + return $this; + } +} diff --git a/idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php b/idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php new file mode 100644 index 0000000..865db54 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php @@ -0,0 +1,8 @@ +name, $fullName) === 0) { + return "GC " . $case->value; + } + } + + return null; + } +} diff --git a/idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php b/idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php new file mode 100644 index 0000000..4239838 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php @@ -0,0 +1,44 @@ +value; + } + + public static function withAlias(string $alias, ProvinceDistrictFields $field): string + { + return "{$alias}.{$field->value}"; + } + + public static function forDistricts(ProvinceDistrictFields $field): string + { + return self::withAlias('Districts', $field); + } + + public static function forCounties(ProvinceDistrictFields $field): string + { + return self::withAlias('Counties', $field); + } + + public static function getCodeRegByRegion(Regions $region): int + { + $regionKey = $region->value; + $configMap = Configure::read("App.mapConfig.cod_reg", []); + + if (!isset($configMap[$regionKey])) { + throw new Exception("Region '{$regionKey}' not found in AppConfig."); + } + + return $configMap[$regionKey]; + } +} diff --git a/idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php b/idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php new file mode 100644 index 0000000..c1a8a31 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php @@ -0,0 +1,28 @@ +channel(); + $channel->queue_declare($queue, false, true, false, false); + $msg = new AMQPMessage(json_encode($m), ['delivery_mode' => 2]); + $channel->basic_publish($msg, '', $queue); + $channel->close(); + $connection->close(); + } +} \ No newline at end of file diff --git a/idrocap_wa/templates/Applicants/citizen_add.php b/idrocap_wa/templates/Applicants/citizen_add.php new file mode 100644 index 0000000..ab25410 --- /dev/null +++ b/idrocap_wa/templates/Applicants/citizen_add.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Creazione Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'disabled' => true, 'value' => $user->name]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'disabled' => true, 'value' => $user->surname]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'disabled' => true, 'value' => $user->tax_code]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true, 'value' => $user->address]); + echo $this->Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'required' => true, 'value' => $user->city]); + echo $this->Form->control('province', ['label' => __('Provincia'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Applicants/citizen_edit.php b/idrocap_wa/templates/Applicants/citizen_edit.php new file mode 100644 index 0000000..f63b258 --- /dev/null +++ b/idrocap_wa/templates/Applicants/citizen_edit.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Creazione Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'disabled' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'disabled' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'disabled' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('province', ['label' => __('Provincia'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Applicants/citizen_view.php b/idrocap_wa/templates/Applicants/citizen_view.php new file mode 100644 index 0000000..6376615 --- /dev/null +++ b/idrocap_wa/templates/Applicants/citizen_view.php @@ -0,0 +1,63 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Dettagli Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('province', ['label' => __('Provincia'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ Form->end(); + ?> + +
+ diff --git a/idrocap_wa/templates/Applicants/edit.php b/idrocap_wa/templates/Applicants/edit.php new file mode 100644 index 0000000..b10c9b5 --- /dev/null +++ b/idrocap_wa/templates/Applicants/edit.php @@ -0,0 +1,71 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: 'province', + fieldName: 'province', + formContext: $applicant ?? null, + fieldRequired: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->province ?? null, + ), + new DistrictCellDto( + fieldId: 'district', + fieldName: 'district', + provinceFieldId: "province", + fieldRequired: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->district ?? null, + entity: $applicant ?? null, + ) + ] + ); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Applicants/view.php b/idrocap_wa/templates/Applicants/view.php new file mode 100644 index 0000000..60a8863 --- /dev/null +++ b/idrocap_wa/templates/Applicants/view.php @@ -0,0 +1,72 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: 'province', + fieldName: 'province', + formContext: $applicant ?? null, + fieldRequired: true, + disabled: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->province ?? null, + ), + new DistrictCellDto( + fieldId: 'district', + fieldName: 'district', + fieldRequired: true, + disabled: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->district ?? null, + ) + ] + ); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ Form->end(); + ?> +
+ diff --git a/idrocap_wa/templates/Capabilities/index.php b/idrocap_wa/templates/Capabilities/index.php new file mode 100644 index 0000000..def20e9 --- /dev/null +++ b/idrocap_wa/templates/Capabilities/index.php @@ -0,0 +1,85 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Gestione competenze'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ +

+
+
+
+
+ +
+ +
+
+
+
+
+ + + + + + + + + + + + + is_configurable ? $style .= 'background-color:#bfbddc;' : ''; + isset($capability->deleted) ? $style .= 'color:red; text-decoration:line-through;' : ''; + $style .= '"'; + + $title = 'title="'; + !$capability->is_configurable ? $title .= __('Competenza non visibile e non configurabile dai non SYSADMIN') . ' ' : ''; + isset($capability->deleted) ? $title .= __('Competenza eliminata dal sistema') : ''; + $title .= '"'; + ?> + > + + + + + + + + +
Paginator->sort('description',__('Descrizione')) ?>Paginator->sort('value', __('Codice')) ?>Paginator->sort('priority', __('Priorità')) ?>Paginator->sort('CapabilityGroups.description', __('Gruppo')) ?>
description) ?>value) ?>priority) ?>capability_group->description) ?> + Form->postLink($capability->is_configurable ? __('Nascondi') : __('Mostra'), ['action' => $capability->is_configurable ? 'hide' : 'show', $capability->id, '?' => $this->request->getQueryParams()], ['class'=>'btn btn-warning btn-xs']) ?> + Form->postLink(isset($capability->deleted) ? __('Ripristina') : __('Cancella'), ['action' => isset($capability->deleted) ? 'restore' : 'delete', $capability->id, '?' => $this->request->getQueryParams()], ['class'=>'btn btn-danger btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/ControllableObjects/get_attachments.php b/idrocap_wa/templates/ControllableObjects/get_attachments.php new file mode 100755 index 0000000..6eb1eb3 --- /dev/null +++ b/idrocap_wa/templates/ControllableObjects/get_attachments.php @@ -0,0 +1,119 @@ + + + + +
+
+

+ 0) ? __('Allegati presenti: {0}', $numberOfAttachments) : __('Nessun Allegato presente') ?> +

+
+
+ + + + + + + + + + + + + + + + + controllable_object->modified))->wasWithinLast('5 minutes') ? "font-weight: bold;background-color:#f8d716" : ""; + ?> + + '; + if($attachment->private) + { + $htmlCode = ''; + } + ?> + + + + + + + + + + + + +
Paginator->sort('Attachments.private', '', ['escape' => false]) ?>';?>Paginator->sort('Attachments.original_file_name', __('Nome')) ?>Paginator->sort('Attachments.relevant', '', ['escape' => false]) ?>Paginator->sort('Attachments.original_file_size', __('Dimensione')) ?>Paginator->sort('Attachments.mimetype', __('Tipo')) ?>Paginator->sort('Attachments.upload_date', __('Caricato il')) ?>Paginator->sort('Creator.surname', __('Da')) ?>
original_file_name) ?>relevant ? '' : '' ?>human_original_file_size) ?>mimetype) ?>upload_date) ?>controllable_object->creator) ?> + Html->link(__('Visualizza'), ['controller' => 'attachments', 'action' => 'view', $attachment->file_name], ['target' => '_blank', 'class' => 'btn btn-info btn-xs', 'style' => 'margin-right: 5px;', 'data-mimetype' => $attachment->mimetype]); + if (isset($removecurrentfiles) && $removecurrentfiles == "true") { + echo $this->Html->link(__('Segna da eliminare'), ['controller' => 'attachments', 'action' => 'markAsDeleted', $attachment->controllable_object_id], ['target' => '_blank', 'class' => 'btn btn-danger btn-xs', 'style' => 'margin-right: 5px;']); + } else { + echo $this->Html->link($attachment->relevant ? __('Segna come non rilevante') : __('Segna come rilevante'), ['controller' => 'attachments', 'action' => 'markAsRelevant', $attachment->file_name], ['id' => $attachment->controllable_object_id, 'target' => '_blank', 'class' => 'btn btn-warning btn-xs', 'style' => 'margin-right: 5px;']); + } + ?> +
+
+ +
diff --git a/idrocap_wa/templates/Dashboard/index.php b/idrocap_wa/templates/Dashboard/index.php new file mode 100644 index 0000000..6b392db --- /dev/null +++ b/idrocap_wa/templates/Dashboard/index.php @@ -0,0 +1,32 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + ], + ]); +?> +
+
+

+ +

+
+
+ Cell('Map', [ + [-1, -5], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + null, // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+ +
+ \ No newline at end of file diff --git a/idrocap_wa/templates/Deliveries/index.php b/idrocap_wa/templates/Deliveries/index.php new file mode 100644 index 0000000..7a45ddb --- /dev/null +++ b/idrocap_wa/templates/Deliveries/index.php @@ -0,0 +1,284 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description); ?> +

+
+
+ + + + + +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
mobile_phone_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'MobilePhones', 'action' => 'edit', $mobile_phone->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $mobile_phone->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare il Cellulare "{0}" ?', $mobile_phone->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
fax_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'Faxes', 'action' => 'edit', $fax->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $fax->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare il Fax "{0}" ?', $fax->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
email_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'Emails', 'action' => 'edit', $email->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $email->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'Email "{0}" ?', $email->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + +
phone_description->description) ?>value) ?> + Html->link(__('Modifica'), ['controller' => 'Phones', 'action' => 'edit', $phone->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $phone->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare il Telefono "{0}" ?', $phone->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + +
value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'TelegramChats', 'action' => 'edit', $telegram_chat->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $telegram_chat->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare la Chat Telegram con ID "{0}" ?', $telegram_chat->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
pec_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'Pecs', 'action' => 'edit', $pec->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $pec->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare la PEC "{0}" ?', $pec->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Emails/add.php b/idrocap_wa/templates/Emails/add.php new file mode 100644 index 0000000..a0c6040 --- /dev/null +++ b/idrocap_wa/templates/Emails/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Email'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($email, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Email')]); + echo $this->Form->control('email_description_id', ['label' => __('Descrizione'), 'options' => $emailDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Emails/edit.php b/idrocap_wa/templates/Emails/edit.php new file mode 100644 index 0000000..a3cc434 --- /dev/null +++ b/idrocap_wa/templates/Emails/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Email'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $email->delivery->actor->description) ?> +

+
+ Form->create($email, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Email')]); + echo $this->Form->control('email_description_id', ['label' => __('Descrizione'), 'options' => $emailDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Error/error400.php b/idrocap_wa/templates/Error/error400.php new file mode 100644 index 0000000..eeaa6f9 --- /dev/null +++ b/idrocap_wa/templates/Error/error400.php @@ -0,0 +1,49 @@ +layout = 'default'; + +if (Configure::read('debug')) : + $this->layout = 'dev_error'; + + $this->assign('title', $message); + $this->assign('templateName', 'error400.php'); + + $this->start('file'); +?> +queryString)) : ?> +

+ SQL Query: + queryString) ?> +

+ +params)) : ?> + SQL Query Params: + params) ?> + +element('auto_table_warning') ?> +end(); +endif; +?> +
+
+
+
+
+
+
+
+

+

'{$url}'") ?>

+

+
+

Html->link(__('Torna indietro'), 'javascript:history.back()') ?>

diff --git a/idrocap_wa/templates/Error/error500.php b/idrocap_wa/templates/Error/error500.php new file mode 100644 index 0000000..8f52f47 --- /dev/null +++ b/idrocap_wa/templates/Error/error500.php @@ -0,0 +1,53 @@ +layout = 'default'; + +if (Configure::read('debug')) : + $this->layout = 'dev_error'; + + $this->assign('title', $message); + $this->assign('templateName', 'error500.php'); + + $this->start('file'); +?> +queryString)) : ?> +

+ SQL Query: + queryString) ?> +

+ +params)) : ?> + SQL Query Params: + params) ?> + + + Error in: + getFile()), $error->getLine()) ?> + +element('auto_table_warning'); + + $this->end(); +endif; +?> +
+
+
+
+
+
+
+
+

+

'{$url}'") ?>

+

+
+

Html->link(__('Torna indietro'), 'javascript:history.back()') ?>

diff --git a/idrocap_wa/templates/Faxes/add.php b/idrocap_wa/templates/Faxes/add.php new file mode 100644 index 0000000..cb3250e --- /dev/null +++ b/idrocap_wa/templates/Faxes/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Fax'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($fax, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Fax')]); + echo $this->Form->control('fax_description_id', ['label' => __('Descrizione'), 'options' => $faxDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Faxes/edit.php b/idrocap_wa/templates/Faxes/edit.php new file mode 100644 index 0000000..8a37561 --- /dev/null +++ b/idrocap_wa/templates/Faxes/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Fax'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $fax->delivery->actor->description) ?> +

+
+ Form->create($fax, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Fax')]); + echo $this->Form->control('fax_description_id', ['label' => __('Descrizione'), 'options' => $faxDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Filters/get_filter_input.php b/idrocap_wa/templates/Filters/get_filter_input.php new file mode 100644 index 0000000..b159ed8 --- /dev/null +++ b/idrocap_wa/templates/Filters/get_filter_input.php @@ -0,0 +1 @@ +Cell('FilterInput', [$filter_id]) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Groups/add.php b/idrocap_wa/templates/Groups/add.php new file mode 100644 index 0000000..c385218 --- /dev/null +++ b/idrocap_wa/templates/Groups/add.php @@ -0,0 +1,61 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Nuovo Profilo Utente'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($group, ['role' => 'form']); ?> +
+ Form->control('description', ['label' => __('Descrizione')]); + echo $this->Form->control('is_default', ['label' => __('Profilo Default')]); + echo $this->Form->control('child_groups._ids', ['label' => __('Profili associati'), 'options' => $child_groups, 'multiple' => true, 'style="width: 100%']); + ?> +
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/Groups/edit.php b/idrocap_wa/templates/Groups/edit.php new file mode 100644 index 0000000..a3fe706 --- /dev/null +++ b/idrocap_wa/templates/Groups/edit.php @@ -0,0 +1,66 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Profilo Utente'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'groups', 'action' => 'view', $group->id], + ], + [ + 'title' => __('Modifica Profilo Utente'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+
+ Form->create($group, ['role' => 'form']); ?> +
+ Form->control('description', ['label' => __('Descrizione')]); + echo $this->Form->control('is_default', ['label' => __('Profilo Default')]); + echo $this->Form->control('child_groups._ids', ['label' => __('Profili associati'), 'options' => $child_groups, 'multiple' => true, 'style="width: 100%']); + ?> +
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/Groups/handle_capabilities.php b/idrocap_wa/templates/Groups/handle_capabilities.php new file mode 100644 index 0000000..9f87622 --- /dev/null +++ b/idrocap_wa/templates/Groups/handle_capabilities.php @@ -0,0 +1,75 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Profilo Utente'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'groups', 'action' => 'view', $group->id], + ], + [ + 'title' => __('Gestione competenze'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ description) ?> +

+
+ + Form->create($group, ['role' => 'form']); ?> +
+ Form->control('description', ['type' => 'hidden']); + ?> +
+ + capabilities) > 0): ?> +
+ description); ?> + + + capabilities as $capability): ?> + id; ?> + + + + + + + +
is_configurable ? 'style="background-color:#bfbddc;" title="' . __('Competenza non visibile e non configurabile dai non SYSADMIN') . '"' : '' ?>>priority == 1 ? $this->Form->control('capabilities._ids[]', ['id' => "capability-id-$capability_id", 'value' => $capability->id, 'label' => $capability->description . (isset($capability->longdescription) ? ' (' . $capability->longdescription . ')' : ''), 'type' => 'checkbox', 'required' => false, 'checked' => in_array($capability->id, $group_capability_ids)]) : '' ?>is_configurable ? 'style="background-color:#bfbddc;" title="' . __('Competenza non visibile e non configurabile dai non SYSADMIN') . '"' : '' ?>>priority == 2 ? $this->Form->control('capabilities._ids[]', ['id' => "capability-id-$capability_id", 'value' => $capability->id, 'label' => $capability->description . (isset($capability->longdescription) ? ' (' . $capability->longdescription . ')' : ''), 'type' => 'checkbox', 'required' => false, 'checked' => in_array($capability->id, $group_capability_ids)]) : '' ?>is_configurable ? 'style="background-color:#bfbddc;" title="' . __('Competenza non visibile e non configurabile dai non SYSADMIN') . '"' : '' ?>>priority == 3 ? $this->Form->control('capabilities._ids[]', ['id' => "capability-id-$capability_id", 'value' => $capability->id, 'label' => $capability->description . (isset($capability->longdescription) ? ' (' . $capability->longdescription . ')' : ''), 'type' => 'checkbox', 'required' => false, 'checked' => in_array($capability->id, $group_capability_ids)]) : '' ?>
+
+ + +
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Groups/index.php b/idrocap_wa/templates/Groups/index.php new file mode 100644 index 0000000..2bc379f --- /dev/null +++ b/idrocap_wa/templates/Groups/index.php @@ -0,0 +1,63 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('description',__('Descrizione')) ?>Paginator->sort('is_default', __('Profilo Default')) ?>
description) ?>is_default ? __('SI') : __('NO') ?>child_groups_csv ?> + Html->link(__('Dettaglio'), ['action' => 'view', $group->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $group->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $group->id], ['confirm' => __('Sei sicuro che vuoi cancellare il profilo "{0}" ?', $group->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Groups/view.php b/idrocap_wa/templates/Groups/view.php new file mode 100644 index 0000000..90a714e --- /dev/null +++ b/idrocap_wa/templates/Groups/view.php @@ -0,0 +1,45 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Profilo Utente'), + 'icon' => 'fa fa-info', + ], + ]); +?> + +
+
+

+
+
+
+
+
description) ?>
+
+
is_default ? __('SI') : __('NO') ?>
+
+
child_groups_csv ?>
+
+
+ +
diff --git a/idrocap_wa/templates/Maps/index.php b/idrocap_wa/templates/Maps/index.php new file mode 100644 index 0000000..3cc1f79 --- /dev/null +++ b/idrocap_wa/templates/Maps/index.php @@ -0,0 +1,149 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => 'Mappe', + 'icon' => 'fa fa-map', + ], + ]); +?> + +
+
+

+ +

+
+
+ Form->control('feature_collection', ['type' => 'text', 'readonly' => true, 'label' => __('Campo esistente appartenente al form ospite'), 'id' => 'feature-collection-custom1', 'value' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[14.379508819839112,37.75776939310461],[15.079779119829889,37.74925139070119],[14.74580405368044,37.227801841878815],[14.379508819839112,37.75776939310461]]]},"properties":null},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[13.302169896776373,37.83438727544886],[13.33565484759548,37.8721796404016],[13.359158669099903,37.9143809499671],[13.371778122610326,37.95936327940137],[13.373028249605412,38.00539445333166],[13.362861008405815,38.0507051513184],[13.341667120388989,38.09355695996422],[13.310261054785746,38.13230874682358],[13.269849729084495,38.165478870642175],[13.221986127869002,38.19180096750125],[13.168509622491761,38.21027134460931],[13.111475285064454,38.220186354514],[13.053074913189183,38.221168496367],[12.995552800405811,38.213180384842815],[12.941119489249829,38.19652613223133],[12.89186682134241,38.17184009894592],[12.849687549090019,38.140063377845536],[12.816202598270912,38.10240878417548],[12.792698776766489,38.06031551994914],[12.780079323256066,38.01539506079607],[12.77882919626098,37.96937016275294],[12.788996437460577,37.924009190796056],[12.810190325477404,37.881058212202475],[12.841596391080646,37.84217345733417],[12.8820077167819,37.80885681076607],[12.92987131799739,37.782396943193774],[12.983347823374631,37.76381852162746],[13.040382160801938,37.75384164211793],[13.098782532677207,37.75285322445332],[13.156304645460581,37.76089160937822],[13.210737956616564,37.77764503105661],[13.259990624523983,37.80246403167463],[13.302169896776373,37.83438727544886]]]},"properties":null},{"type":"Feature","geometry":{"type":"Point","coordinates":[14.00244019676715,37.71516957586901]},"properties":null}]}']); + + echo $this->Cell('Map', [ + [-1], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Evento'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => true, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'feature_collection' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'feature-collection-custom1', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'feature_collection_custom1', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Collezione di geometrie'), + ], + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude-custom2', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude_custom2', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Longitudine'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude-custom3', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude_custom3', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Latitudine'), + ], + 'coordinates' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'coordinates-custom4', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'coordinates_custom4', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinate (Longitudine Latitudine)'), + ], + 'cap' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'cap', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'cap', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Cap'), + ], + 'province' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'province', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'province', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Provincia'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'address', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'address', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Indirizzo'), + ], + 'description' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'description', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'description', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Descrizione luogo'), + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+ +
diff --git a/idrocap_wa/templates/MobilePhones/add.php b/idrocap_wa/templates/MobilePhones/add.php new file mode 100644 index 0000000..5bc4fb9 --- /dev/null +++ b/idrocap_wa/templates/MobilePhones/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Cellulare'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($mobilePhone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Cellulare')]); + echo $this->Form->control('mobile_phone_description_id', ['label' => __('Descrizione'), 'options' => $mobilePhoneDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/MobilePhones/edit.php b/idrocap_wa/templates/MobilePhones/edit.php new file mode 100644 index 0000000..2496d6c --- /dev/null +++ b/idrocap_wa/templates/MobilePhones/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Cellulare'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $mobilePhone->delivery->actor->description) ?> +

+
+ Form->create($mobilePhone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Cellulare')]); + echo $this->Form->control('mobile_phone_description_id', ['label' => __('Descrizione'), 'options' => $mobilePhoneDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Notifications/index.php b/idrocap_wa/templates/Notifications/index.php new file mode 100644 index 0000000..601379c --- /dev/null +++ b/idrocap_wa/templates/Notifications/index.php @@ -0,0 +1,4 @@ +Notifications->create($user_notifications) ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/Notifications/read_all.php b/idrocap_wa/templates/Notifications/read_all.php new file mode 100644 index 0000000..af458c8 --- /dev/null +++ b/idrocap_wa/templates/Notifications/read_all.php @@ -0,0 +1,5 @@ +Notifications->create($user_notifications) ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/Organisations/add.php b/idrocap_wa/templates/Organisations/add.php new file mode 100644 index 0000000..55f90e8 --- /dev/null +++ b/idrocap_wa/templates/Organisations/add.php @@ -0,0 +1,197 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'organisations', 'action' => 'index'], + ], + [ + 'title' => __('Nuova Organizzazione'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($organisation, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('actor.description', ['label' => __('Nome')]); ?> +
+
+ Form->control('acronym', ['label' => __('Acronimo')]); ?> +
+
+ Form->control('organisation_type_id', ['label' => __('Tipo organizzazione'), 'style="width: 100%']); ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Organizzazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'feature_collection' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => true, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'feature-collection', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'feature_collection', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => null, + ], + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => true, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Longitudine'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => true, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Latitudine'), + ], + 'coordinates' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'coordinates', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'coordinates', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinate (Longitudine Latitudine)'), + ], + 'cap' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'cap', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'cap', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Cap'), + ], + 'province' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'province', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'province', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Provincia'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'address', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'address', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Indirizzo'), + ], + 'description' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'description', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'description', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Descrizione luogo'), + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+
+ Form->control('coordinates', ['label' => __('Coordinate (Longitudine Latitudine)'), 'type' => 'text', 'readonly' => true]); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('district', ['label' => __('Comune')]); ?> +
+
+ Form->control('province', ['label' => __('Provincia')]); ?> +
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/Organisations/edit.php b/idrocap_wa/templates/Organisations/edit.php new file mode 100644 index 0000000..1e94bb6 --- /dev/null +++ b/idrocap_wa/templates/Organisations/edit.php @@ -0,0 +1,118 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'organisations', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Organizzazione'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'organisations', 'action' => 'view', $organisation->id], + ], + [ + 'title' => __('Modifica Organizzazione'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($organisation, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('actor.description', ['label' => __('Nome')]); ?> +
+
+ Form->control('acronym', ['label' => __('Acronimo')]); ?> +
+
+ Form->control('organisation_type_id', ['label' => __('Tipo organizzazione'), 'style="width: 100%']); ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Organizzazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+
+ Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('coordinates', ['label' => __('Coordinate (Longitudine Latitudine)'), 'type' => 'text', 'readonly' => true]); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('district', ['label' => __('Comune')]); ?> +
+
+ Form->control('province', ['label' => __('Provincia')]); ?> +
+ +
+ controllable_object_interface)) { + $attachment_options = [ + 'filepicker' => true, + 'coId' => $organisation->controllable_object_interface->controllable_object_id, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'view_in_frame_with_id' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]; + } else { + $attachment_options = [ + 'filepicker' => true, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]; + } + echo $this->element('attachments', $attachment_options); + ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/Organisations/index.php b/idrocap_wa/templates/Organisations/index.php new file mode 100644 index 0000000..bdd562c --- /dev/null +++ b/idrocap_wa/templates/Organisations/index.php @@ -0,0 +1,75 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_organisations ? __('{0} su {1}', $filtered_organisations, $total_organisations) : $total_organisations) ?> +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('Actors.description', __('Descrizione')) ?>Paginator->sort('acronym', __('Acronimo')) ?>Paginator->sort('OrganisationTypes.description', __('Tipologia')) ?>Paginator->sort('address', __('Indirizzo')) ?>Paginator->sort('cap', __('CAP')) ?>Paginator->sort('district', __('Comune')) ?>Paginator->sort('province', __('Provincia')) ?>
actor->description) ?>acronym) ?>organisation_type->description) ?>address) ?>cap) ?>district) ?>province) ?>actor->contacts) ?> + Html->link(__('Dettaglio'), ['action' => 'view', $organisation->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $organisation->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $organisation->id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'organizzazione "{0}" ?', $organisation->actor->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Organisations/view.php b/idrocap_wa/templates/Organisations/view.php new file mode 100644 index 0000000..badad7b --- /dev/null +++ b/idrocap_wa/templates/Organisations/view.php @@ -0,0 +1,99 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'organisations', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Organizzazione'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($organisation, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('actor.description', ['label' => __('Nome')]); ?> +
+
+ Form->control('acronym', ['label' => __('Acronimo')]); ?> +
+
+ Form->control('organisation_type_id', ['label' => __('Tipo organizzazione'), 'style="width: 100%', 'disabled' => true]); ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Organizzazione'), + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> +
+
+ Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('coordinates', ['label' => __('Coordinate (Longitudine Latitudine)'), 'type' => 'text']); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('district', ['label' => __('Comune')]); ?> +
+
+ Form->control('province', ['label' => __('Provincia')]); ?> +
+
+ Form->control('deliveries', ['label' => __('Recapiti'), 'type' => 'text', 'value' => $organisation->actor->contacts]); ?> +
+
+ controllable_object_interface)) { + echo $this->element('attachments', [ + 'coId' => $organisation->controllable_object_interface->controllable_object_id, + 'viewer' => true + ]); + } + ?> +
+
+ Form->end(); ?> +
+ +
+ + diff --git a/idrocap_wa/templates/Pecs/add.php b/idrocap_wa/templates/Pecs/add.php new file mode 100644 index 0000000..d6c8b45 --- /dev/null +++ b/idrocap_wa/templates/Pecs/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi PEC'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($pec, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('PEC')]); + echo $this->Form->control('pec_description_id', ['label' => __('Descrizione'), 'options' => $pecDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Pecs/edit.php b/idrocap_wa/templates/Pecs/edit.php new file mode 100644 index 0000000..3bac119 --- /dev/null +++ b/idrocap_wa/templates/Pecs/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica PEC'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $pec->delivery->actor->description) ?> +

+
+ Form->create($pec, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('PEC')]); + echo $this->Form->control('pec_description_id', ['label' => __('Descrizione'), 'options' => $pecDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Phones/add.php b/idrocap_wa/templates/Phones/add.php new file mode 100644 index 0000000..d5c6e02 --- /dev/null +++ b/idrocap_wa/templates/Phones/add.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Telefono'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($phone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Telefono')]); + echo $this->Form->control('phone_description_id', ['label' => __('Descrizione'), 'options' => $phoneDescriptions, 'empty' => false]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Phones/edit.php b/idrocap_wa/templates/Phones/edit.php new file mode 100644 index 0000000..b346733 --- /dev/null +++ b/idrocap_wa/templates/Phones/edit.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Telefono'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $phone->delivery->actor->description) ?> +

+
+ Form->create($phone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Telefono')]); + echo $this->Form->control('phone_description_id', ['label' => __('Descrizione'), 'options' => $phoneDescriptions, 'empty' => false]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Privacy/accept_privacy.php b/idrocap_wa/templates/Privacy/accept_privacy.php new file mode 100644 index 0000000..c1ba8d1 --- /dev/null +++ b/idrocap_wa/templates/Privacy/accept_privacy.php @@ -0,0 +1,29 @@ +Breadcrumb->render($breadcrumbs); ?> + +
+
+

+
+ Form->create($privacy, ['role' => 'form']); ?> +
+
+
+ Form->input('description', ['type' => 'textarea', 'id' => 'description']); ?> +
+
+
+ + Form->end(); ?> +
+ +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Privacy/edit.php b/idrocap_wa/templates/Privacy/edit.php new file mode 100644 index 0000000..8ff3081 --- /dev/null +++ b/idrocap_wa/templates/Privacy/edit.php @@ -0,0 +1,24 @@ +Breadcrumb->render($breadcrumbs); ?> + +
+
+

+
+ Form->create($privacy, ['role' => 'form']); ?> +
+
+
+ Form->input('description', ['type' => 'textarea', 'id' => 'description']); ?> +
+
+
+ + Form->end(); ?> +
+ +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Privacy/view.php b/idrocap_wa/templates/Privacy/view.php new file mode 100644 index 0000000..7b723a7 --- /dev/null +++ b/idrocap_wa/templates/Privacy/view.php @@ -0,0 +1,19 @@ +Breadcrumb->render($breadcrumbs); ?> + +
+
+

+
+ Form->create($privacy, ['role' => 'form']); ?> +
+
+
+ Form->input('description', ['type' => 'textarea', 'id' => 'description']); ?> +
+
+
+ Form->end(); ?> +
+ +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Privacy/view_public.php b/idrocap_wa/templates/Privacy/view_public.php new file mode 100644 index 0000000..bc7b4c0 --- /dev/null +++ b/idrocap_wa/templates/Privacy/view_public.php @@ -0,0 +1,10 @@ +Form->create($privacy, ['role' => 'form']); ?> +
+
+ description) ? $this->Form->input('description', ['type' => 'textarea', 'id' => 'description']) : ''; ?> +
+
+Form->end(); ?> + +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Tags/add.php b/idrocap_wa/templates/Tags/add.php new file mode 100644 index 0000000..87514ef --- /dev/null +++ b/idrocap_wa/templates/Tags/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei tags'), + 'icon' => 'fa fa-list', + 'url' => ['action' => 'index'], + ], + [ + 'title' => __('Crea tag'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($tag, ['role' => 'form', 'type' => 'file', 'id' => 'editTag']); ?> +
+
+
+ Form->control('description', ['label' => __('Descrizione')]); ?> +
+
+ Form->control('code', ['label' => __('Codice')]); ?> +
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'required' => true, + 'upload_single' => true, + ]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Tags/edit.php b/idrocap_wa/templates/Tags/edit.php new file mode 100644 index 0000000..73f5144 --- /dev/null +++ b/idrocap_wa/templates/Tags/edit.php @@ -0,0 +1,55 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei tags'), + 'icon' => 'fa fa-list', + 'url' => ['action' => 'index'], + ], + [ + 'title' => __('Modifica tag'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($tag, ['role' => 'form', 'type' => 'file', 'id' => 'editTag']); ?> +
+
+
+ Form->control('description', ['label' => __('Descrizione')]); ?> +
+
+ Form->control('code', ['label' => __('Codice')]); ?> +
+
+ element('attachments', [ + 'coId' => isset($tag->controllable_object_id) ? $tag->controllable_object_id : null, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'required' => false, + 'upload_single' => true, + ]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Tags/index.php b/idrocap_wa/templates/Tags/index.php new file mode 100644 index 0000000..cd61756 --- /dev/null +++ b/idrocap_wa/templates/Tags/index.php @@ -0,0 +1,63 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli tags'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('id',__('Id')) ?>Paginator->sort('description', __('Descrizione')) ?>Paginator->sort('code', __('Codice')) ?>
id) ?>description) ?>code) ?> + Html->link(__('Dettaglio'), ['action' => 'view', $tag->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $tag->id], ['class'=>'btn btn-warning btn-xs']) : null ?> +
+
+ +
+ diff --git a/idrocap_wa/templates/Tags/view.php b/idrocap_wa/templates/Tags/view.php new file mode 100644 index 0000000..23b79de --- /dev/null +++ b/idrocap_wa/templates/Tags/view.php @@ -0,0 +1,52 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei tags'), + 'icon' => 'fa fa-list', + 'url' => ['action' => 'index'], + ], + [ + 'title' => __('Dettaglio tag'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($tag, ['role' => 'form', 'type' => 'file', 'id' => 'editTag']); ?> +
+
+
+ Form->control('description', ['label' => __('Descrizione'), 'disabled' => true]); ?> +
+
+ Form->control('code', ['label' => __('Codice'), 'disabled' => true]); ?> +
+
+ element('attachments', [ + 'coId' => $tag->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + ]); ?> +
+
+
+ Form->end(); ?> + +
diff --git a/idrocap_wa/templates/TelegramChats/add.php b/idrocap_wa/templates/TelegramChats/add.php new file mode 100644 index 0000000..6ebc23d --- /dev/null +++ b/idrocap_wa/templates/TelegramChats/add.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Chat Telegram'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($telegram_chat, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Chat Telegram ID')]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/TelegramChats/edit.php b/idrocap_wa/templates/TelegramChats/edit.php new file mode 100644 index 0000000..f5bdb3d --- /dev/null +++ b/idrocap_wa/templates/TelegramChats/edit.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Chat Telegram'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $telegram_chat->delivery->actor->description) ?> +

+
+ Form->create($telegram_chat, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Chat Telegram ID')]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Users/add.php b/idrocap_wa/templates/Users/add.php new file mode 100644 index 0000000..453d8eb --- /dev/null +++ b/idrocap_wa/templates/Users/add.php @@ -0,0 +1,108 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'users', 'action' => 'index'], + ], + [ + 'title' => __('Nuovo Utente'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($user, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('username', ['label' => __('Nome utente')]); ?> +
+
+ Form->control('name', ['label' => __('Nome')]); ?> +
+
+ Form->control('surname', ['label' => __('Cognome')]); ?> +
+
+ Form->control('tax_code', ['label' => __('Codice Fiscale')]); ?> +
+
+ Form->control('password', ['label' => __('Password')]); ?> +
+
+ Form->control('birthday', ['type' => 'date', 'label' => __('Data di nascita'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('birthplace', ['label' => __('Luogo di nascita')]); ?> +
+
+ Form->control('gender', ['label' => __('Sesso'), 'type' => 'select', 'options' => ['M' => 'M', 'F' => 'F'], 'empty' => false, 'style="width: 100%']); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('city', ['label' => __('Città')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('language_id', ['label' => __('Lingua preferita'), 'style="width: 100%']); ?> +
+
+ Form->control('organisation_id', ['label' => __('Organizzazione'), 'empty' => true, 'style="width: 100%']); ?> +
+
+ Form->control('user_photo', ['label' => __('Foto del profilo (solo jpeg di dimensioni 160x160!)'), 'type' => 'file', 'accept' => '.jpeg']); ?> +
+ +
+ Form->control('groups._ids', ['label' => __('Profili'), 'options' => $groups, 'multiple' => true, 'disabled' => !$can_handle_profiles, 'style="width: 100%']); ?> +
+ +
+
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/Users/add_citizen.php b/idrocap_wa/templates/Users/add_citizen.php new file mode 100644 index 0000000..5429e85 --- /dev/null +++ b/idrocap_wa/templates/Users/add_citizen.php @@ -0,0 +1,256 @@ + +Html->css('/bower_components/select2/dist/css/select2.min'); ?> +
+
+

+
+ Form->create($user, ['role' => 'form', 'type' => 'file', 'id' => 'add-citizen-js']) ?> +
+
+
+ Form->control('username', ['label' => __('Nome utente')]); ?> +
+
+ getName() ?? ''): ?> + Form->control('name', ['label' => __('Nome'), + 'value' => $citizenRegistrationData?->getName() ?? '', + 'readonly' => $citizenRegistrationData?->getName() ? true : false + ]); ?> + + Form->control('name', ['label' => __('Nome'), 'required' => true]); ?> + +
+
+ getSurname() ?? ''): ?> + Form->control('surname', ['label' => __('Cognome'), + 'value' => $citizenRegistrationData?->getSurname() ?? '', + 'readonly' => $citizenRegistrationData?->getSurname() ? true : false + ]); ?> + + Form->control('surname', ['label' => __('Cognome'), 'required' => true]); ?> + +
+
+ getFiscalCode() ?? ''): ?> + Form->control('tax_code', ['label' => __('Codice Fiscale'), + 'value' => $citizenRegistrationData?->getFiscalCode() ?? '', + 'readonly' => $citizenRegistrationData?->getFiscalCode() ? true : false + ]); ?> + + Form->control('tax_code', ['label' => __('Codice Fiscale'), 'required' => true]); ?> + +
+ +
+ Form->control('email', ['label' => __('Email'), 'required' => true, 'type' => 'email']); ?> +
+ +
+ Form->control('password', ['label' => __('Password')]); ?> +
+ +
+ Form->control('confirmPassword', ['label' => __('Conferma password'), 'type' => 'password', 'required' => true]); ?> +
+ +
+ getBirthdate() ?? ''): ?> + Form->control('birthday', ['label' => __('Data di nascita'), + 'type' => 'date', + 'value' => $citizenRegistrationData?->getBirthdate() ?? '', + 'readonly' => $citizenRegistrationData?->getBirthdate() ? true : false + ]); ?> + + Form->control('birthday', ['type' => 'date', 'label' => __('Data di nascita'), 'max' => $today->format('Y-m-d')]); ?> + +
+
+ Form->control('birthplace', ['label' => __('Luogo di nascita')]); ?> +
+
+ getGender() ?? ''): ?> + Form->control('gender', ['label' => __('Sesso'), + 'value' => $citizenRegistrationData?->getGender() ?? '', + 'readonly' => $citizenRegistrationData?->getGender() ? true : false + ]); ?> + + Form->control('gender', ['label' => __('Sesso'), 'type' => 'select', 'options' => ['M' => 'M', 'F' => 'F'], 'empty' => false, 'style="width: 100%']); ?> + + +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('city', ['label' => __('Città')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('language_id', ['label' => __('Lingua preferita'), 'style="width: 100%']); ?> +
+
+ Form->control('user_photo', ['label' => __('Foto del profilo (solo jpeg di dimensioni 160x160!)'), 'type' => 'file', 'accept' => '.jpeg']); ?> +
+
+
+ + Form->end(); ?> +
+ +Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + +Html->script('/bower_components/select2/dist/js/select2.min'); ?> + + + + diff --git a/idrocap_wa/templates/Users/choose_new_password.php b/idrocap_wa/templates/Users/choose_new_password.php new file mode 100644 index 0000000..89aa06c --- /dev/null +++ b/idrocap_wa/templates/Users/choose_new_password.php @@ -0,0 +1,10 @@ +
+ Form->create() ?> +
+ + Form->control('new_password', ['label' => __('Digita la nuova password'), 'type' => 'password']) ?> + Form->control('confirm_new_password', ['label' => __('Ridigita la nuova password'), 'type' => 'password']) ?> +
+ Form->button(__('Salva'), ['class' => 'btn btn-success']); ?> + Form->end() ?> +
\ No newline at end of file diff --git a/idrocap_wa/templates/Users/edit.php b/idrocap_wa/templates/Users/edit.php new file mode 100644 index 0000000..d3c93cd --- /dev/null +++ b/idrocap_wa/templates/Users/edit.php @@ -0,0 +1,112 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Utente'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'users', 'action' => 'view', $user->id], + ], + [ + 'title' => __('Modifica Utente'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($user, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('username', ['label' => __('Nome utente')]); ?> +
+
+ Form->control('name', ['label' => __('Nome')]); ?> +
+
+ Form->control('surname', ['label' => __('Cognome')]); ?> +
+
+ Form->control('tax_code', ['label' => __('Codice Fiscale')]); ?> +
+
+ Form->control('password', ['label' => __('Password')]); ?> +
+
+ Form->control('birthday', ['type' => 'date', 'label' => __('Data di nascita'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('birthplace', ['label' => __('Luogo di nascita')]); ?> +
+
+ Form->control('gender', ['label' => __('Sesso'), 'type' => 'select', 'options' => ['M' => 'M', 'F' => 'F'], 'empty' => false, 'style="width: 100%']); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('city', ['label' => __('Città')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('language_id', ['label' => __('Lingua preferita'), 'style="width: 100%']); ?> +
+
+ Form->control('organisation_id', ['label' => __('Organizzazione'), 'style="width: 100%']); ?> +
+
+ Form->control('user_photo', ['label' => __('Foto del profilo (solo jpeg di dimensioni 160x160!)'), 'type' => 'file', 'accept' => '.jpeg']); ?> +
+ +
+ Form->control('groups._ids', ['label' => __('Profili'), 'options' => $groups, 'multiple' => true, 'disabled' => !$can_handle_profiles, 'style="width: 100%']); ?> +
+ +
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/Users/index.php b/idrocap_wa/templates/Users/index.php new file mode 100644 index 0000000..0cdd4c0 --- /dev/null +++ b/idrocap_wa/templates/Users/index.php @@ -0,0 +1,71 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_users ? __('{0} su {1}', $filtered_users, $total_users) : $total_users) ?> +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('surname',__('Cognome')) ?>Paginator->sort('name', __('Nome')) ?>Paginator->sort('username', __('Username')) ?>Paginator->sort('OrganisationActors.description', __('Organizzazione')) ?>
surname) ?>name) ?>username) ?>actor->contacts) ?>profiles) ?>organisation->actor->description) ?> + Html->link(__('Dettaglio'), ['action' => 'view', $user->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $user->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $user->id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'utente "{0}" ?', $user->actor->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Users/login.php b/idrocap_wa/templates/Users/login.php new file mode 100644 index 0000000..4f02e58 --- /dev/null +++ b/idrocap_wa/templates/Users/login.php @@ -0,0 +1,27 @@ + +
+ Form->create() ?> +
+ + Form->control('user_timezone', ['type' => 'hidden']) ?> + Form->control('username') ?> + Form->control('password') ?> +
Form->control('remember_me', ['label' => __(' Rimani connesso'), 'type' => 'checkbox', 'checked' => true]) ?>
+
+
+
+ Form->button(__('Login'), ['class' => 'btn btn-success']); ?> +
+
+ Html->link(__('Accedi con {0}', Configure::read('App.oidc.idp_name', 'OpenID Connect')), ['controller' => 'Users', 'action' => 'login_oidc'], ['class'=>'btn btn-info']) : ''?> +
+
+ Form->end() ?> +
+ diff --git a/idrocap_wa/templates/Users/one_time_password.php b/idrocap_wa/templates/Users/one_time_password.php new file mode 100644 index 0000000..fded58c --- /dev/null +++ b/idrocap_wa/templates/Users/one_time_password.php @@ -0,0 +1,8 @@ +
+ Form->create() ?> +
+ +
+
Form->button(__('Procedi'), ['class' => 'btn btn-success']); ?>
+ Form->end() ?> +
\ No newline at end of file diff --git a/idrocap_wa/templates/Users/password_recovery.php b/idrocap_wa/templates/Users/password_recovery.php new file mode 100644 index 0000000..079cbd2 --- /dev/null +++ b/idrocap_wa/templates/Users/password_recovery.php @@ -0,0 +1,9 @@ +
+ Form->create() ?> +
+ + Form->control('email') ?> +
+ Form->button(__('Richiedi reset password'), ['class' => 'btn btn-success']); ?> + Form->end() ?> +
\ No newline at end of file diff --git a/idrocap_wa/templates/Users/view.php b/idrocap_wa/templates/Users/view.php new file mode 100644 index 0000000..1ebab21 --- /dev/null +++ b/idrocap_wa/templates/Users/view.php @@ -0,0 +1,72 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Utente'), + 'icon' => 'fa fa-info', + ], + ]); +?> +
+
+

+
+ photo): ?> +
+ Html->image("/users/getPhoto/" . $user->photo, array('class' => 'img-circle', 'alt' => 'User Image', 'style' => 'margin-right: 5px;')) ?> + Form->postLink(__('Elimina foto'), ['action' => 'deleteUserPhoto', $user->id], ['confirm' => __('Sei sicuro che vuoi eliminare la foto ?'), 'class'=>'btn btn-danger btn-xs']) ?> +
+ +
+
+
+
username) ?>
+
+
name) ?>
+
+
surname) ?>
+
+
tax_code) ?>
+
+
birthday) ? $user->birthday->format('d/m/Y') : '') ?>
+
+
birthplace) ?>
+
+
gender) ?>
+
+
address) ?>
+
+
city) ?>
+
+
cap) ?>
+
+
language->description) ? $user->language->description : __('Non specificata')) ?>
+
+
organisation->actor->description) ? $user->organisation->actor->description : '') ?>
+
+
profiles) ?>
+
+
actor->contacts) ?>
+
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingArticles/add.php b/idrocap_wa/templates/WaterDrawingArticles/add.php new file mode 100644 index 0000000..2a66599 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/add.php @@ -0,0 +1,45 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingArticles', 'action' => 'index'], + ], + [ + 'title' => __('Nuovo Articolo di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingArticle, ['role' => 'form']); ?> +
+
+
+ Form->control('description', ['label' => __('Articolo')]); ?> +
+
+ Form->control('long_description', ['label' => __('Descrizione')]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingArticles/edit.php b/idrocap_wa/templates/WaterDrawingArticles/edit.php new file mode 100644 index 0000000..9434199 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/edit.php @@ -0,0 +1,45 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingArticles', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Articolo di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingArticle, ['role' => 'form']); ?> +
+
+
+ Form->control('description', ['label' => __('Articolo')]); ?> +
+
+ Form->control('long_description', ['label' => __('Descrizione')]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingArticles/index.php b/idrocap_wa/templates/WaterDrawingArticles/index.php new file mode 100644 index 0000000..39d6d9c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/index.php @@ -0,0 +1,65 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('description',__('Articolo')) ?>Paginator->sort('long_description', __('Descrizione')) ?>Paginator->sort('disabled', __('Abilitato')) ?>
description) ?>long_description) ?>disable ? __('No') : __('Si') ?> + Html->link(__('Dettaglio'), ['action' => 'view', $waterDrawingArticle->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $waterDrawingArticle->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(($waterDrawingArticle->disable ? __('Abilita') : __('Disabilita')), ['action' => 'change_status', $waterDrawingArticle->id], ['confirm' => ($waterDrawingArticle->disable ? __('Sei sicuro che vuoi abilitare l\'articolo "{0}" ?', $waterDrawingArticle->description) : __('Sei sicuro che vuoi disabilitare l\'articolo "{0}" ?', $waterDrawingArticle->description)), 'class'=>'btn btn-info btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingArticle->id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'articolo "{0}" ?', $waterDrawingArticle->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ diff --git a/idrocap_wa/templates/WaterDrawingArticles/view.php b/idrocap_wa/templates/WaterDrawingArticles/view.php new file mode 100644 index 0000000..86f6eb7 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/view.php @@ -0,0 +1,55 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingArticles', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Articolo di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingArticle, ['role' => 'form']); ?> +
+
+
+ Form->control('description', ['label' => __('Articolo')]); ?> +
+
+ Form->control('long_description', ['label' => __('Descrizione')]); ?> +
+
+ Form->control('disabled', ['label' => __('Abilitato'), 'value' => ($waterDrawingArticle->disable ? __('No') : __('Si')), 'disabled' => true]); ?> +
+
+
+ + Form->end(); ?> +
+ diff --git a/idrocap_wa/templates/WaterDrawingDerivations/add.php b/idrocap_wa/templates/WaterDrawingDerivations/add.php new file mode 100644 index 0000000..3da6bad --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/add.php @@ -0,0 +1,250 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi Punto di prelievo/derivazione'), + 'icon' => 'fa fa-add', + ], +]); +?> +
+
+

+
+ Form->create($waterDrawingDerivation, ['role' => 'form', 'type' => 'file']); ?> +
+
+ +
+ Cell('Map', [ + [-2, -3, -4], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'location', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'location', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Contrada/Località'), + ], + 'district_code' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'istat', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'istat', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('ISTAT'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'table_name' => 'geo.rw_watersheds', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'swbcode' => 'swbcode' + ], + ], + [ + 'table_name' => 'geo.cw_draining_areas', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'cw_wise_co' => 'cw-wise-co' + ], + ], + [ + 'table_name' => 'geo.gwbs', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'wbcod' => 'wbcod', + ], + ], + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'COD_COMUNE' => 'cadastral-code', + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_code', ['label' => __('Codice catastale (Belfiore)'), 'type' => 'text']) ?> +
+
+ Form->control('location', ['label' => __('Contrada/Località'), 'type' => 'text']) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->hidden('water_drawing_paperwork_id', ['value' => $water_drawing_paperwork_id]) ?> + Form->control('water_drawing_derivation_type_id', ['label' => __('Tipo di derivazione'), 'options' => $waterDrawingDerivationTypes, 'onChange' => 'setWaterBody()']) ?> +
+
+ Form->control('water_body', ['label' => __('Corpo idrico'), 'type' => 'text']) ?> +
+ + +
+ Form->control('description', ['label' => __('Descrizione'), 'type' => 'text']) ?> +
+ +
+ Form->control('wbcod', ['label' => __('Codice corpo idrico sotterraneo'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('cw_wise_co', ['label' => __('Codice area afferente al corpo idrico marino costiero'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('swbcode', ['label' => __('Codice corpo idrico superficiale'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('istat', ['label' => __('Codice ISTAT'), 'type' => 'text']) ?> +
+
+ Form->control('derivation_status', ['label' => __('Status della derivazione'), 'type' => 'text']) ?> +
+
+ Form->control('withdrawals_amount', ['label' => __('N. prelievi'), 'type' => 'text']) ?> +
+
+ Form->control('annual_volume', ['label' => __('Volume annuo (m^3)'), 'type' => 'number', 'min' => 0]) ?> +
+
+ Form->control('average_flow_rate', ['label' => __('Portata media (l/s)'), 'type' => 'number', 'min' => 0]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+
+ Form->end(); ?> +
+
+ diff --git a/idrocap_wa/templates/WaterDrawingDerivations/edit.php b/idrocap_wa/templates/WaterDrawingDerivations/edit.php new file mode 100644 index 0000000..d1fb035 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/edit.php @@ -0,0 +1,235 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica Punto di prelievo/derivazione'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingDerivation, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_derivation_type_id', ['label' => __('Tipo di derivazione'), 'options' => $waterDrawingDerivationTypes]) ?> +
+
+ Form->control('water_body', ['label' => __('Corpo idrico'), 'type' => 'text']) ?> +
+ + +
+ Form->control('description', ['label' => __('Descrizione'), 'type' => 'text']) ?> +
+ +
+ Form->control('wbcod', ['label' => __('Codice corpo idrico sotterraneo'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('cw_wise_co', ['label' => __('Codice area afferente al corpo idrico marino costiero'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('swbcode', ['label' => __('Codice corpo idrico superficiale'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Cell('Map', [ + [-2, -3, -4], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'location', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'location', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Contrada/Località'), + ], + 'district_code' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'istat', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'istat', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('ISTAT'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'table_name' => 'geo.rw_watersheds', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'swbcode' => 'swbcode' + ], + ], + [ + 'table_name' => 'geo.cw_draining_areas', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'cw_wise_co' => 'cw-wise-co' + ], + ], + [ + 'table_name' => 'geo.gwbs', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'wbcod' => 'wbcod', + ], + ], + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'COD_COMUNE' => 'cadastral-code', + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_code', ['label' => __('Codice catastale (Belfiore)'), 'type' => 'text']) ?> +
+
+ Form->control('location', ['label' => __('Contrada/Località'), 'type' => 'text']) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->control('istat', ['label' => __('Codice ISTAT'), 'type' => 'text']) ?> +
+
+ Form->control('derivation_status', ['label' => __('Status della derivazione'), 'type' => 'text']) ?> +
+
+ Form->control('withdrawals_amount', ['label' => __('N. prelievi'), 'type' => 'text']) ?> +
+
+ Form->control('annual_volume', ['label' => __('Volume annuo (m^3)'), 'type' => 'number', 'min' => 0]) ?> +
+
+ Form->control('average_flow_rate', ['label' => __('Portata media (l/s)'), 'type' => 'number', 'min' => 0]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+
+ Form->end(); ?> +
+
+ diff --git a/idrocap_wa/templates/WaterDrawingDerivations/index.php b/idrocap_wa/templates/WaterDrawingDerivations/index.php new file mode 100644 index 0000000..f333f78 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/index.php @@ -0,0 +1,72 @@ + $waterDrawingDerivations + */ +?> +
+ Html->link(__('New Water Drawing Derivation'), ['action' => 'add'], ['class' => 'button float-right']) ?> +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('water_body') ?>Paginator->sort('district') ?>Paginator->sort('cadastral_code') ?>Paginator->sort('location') ?>Paginator->sort('cadastral_sheet') ?>Paginator->sort('cadastral_parcel') ?>Paginator->sort('latitude') ?>Paginator->sort('longitude') ?>Paginator->sort('istat') ?>Paginator->sort('derivation_status') ?>Paginator->sort('withdrawals_amount') ?>Paginator->sort('annual_volume') ?>Paginator->sort('average_flow_rate') ?>Paginator->sort('water_drawing_derivation_type_id') ?>Paginator->sort('water_drawing_paperwork_id') ?>
Number->format($waterDrawingDerivation->id) ?>water_body) ?>district) ?>cadastral_code) ?>location) ?>cadastral_sheet === null ? '' : $this->Number->format($waterDrawingDerivation->cadastral_sheet) ?>cadastral_parcel === null ? '' : $this->Number->format($waterDrawingDerivation->cadastral_parcel) ?>latitude) ?>longitude) ?>istat) ?>derivation_status) ?>withdrawals_amount === null ? '' : $this->Number->format($waterDrawingDerivation->withdrawals_amount) ?>annual_volume === null ? '' : $this->Number->format($waterDrawingDerivation->annual_volume) ?>average_flow_rate === null ? '' : $this->Number->format($waterDrawingDerivation->average_flow_rate) ?>hasValue('water_drawing_derivation_type') ? $this->Html->link($waterDrawingDerivation->water_drawing_derivation_type->id, ['controller' => 'WaterDrawingDerivationTypes', 'action' => 'view', $waterDrawingDerivation->water_drawing_derivation_type->id]) : '' ?>hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingDerivation->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $waterDrawingDerivation->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $waterDrawingDerivation->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $waterDrawingDerivation->id], ['confirm' => __('Are you sure you want to delete # {0}?', $waterDrawingDerivation->id)]) ?> +
+
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?>

+
+
diff --git a/idrocap_wa/templates/WaterDrawingDerivations/view.php b/idrocap_wa/templates/WaterDrawingDerivations/view.php new file mode 100644 index 0000000..021f894 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/view.php @@ -0,0 +1,104 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli Punto di prelievo/derivazione'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingDerivation, ['id' => 'myForm', 'role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_derivation_type.description', ['label' => __('Tipo di derivazione'), 'type' => 'text', 'required' => false, 'disabled' => true]) ?> +
+
+ Form->control('water_body', ['label' => __('Corpo idrico'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('description', ['label' => __('Descrizione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_code', ['label' => __('Codice catastale (Belfiore)'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('location', ['label' => __('Contrada/Località'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0, 'disabled' => true]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true, 'disabled' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true, 'disabled' => true]) ?> +
+
+ Form->control('istat', ['label' => __('Codice ISTAT'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('derivation_status', ['label' => __('Status della derivazione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('withdrawals_amount', ['label' => __('N. prelievi'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('annual_volume', ['label' => __('Volume annuo (m^3)'), 'type' => 'number', 'min' => 0, 'disabled' => true]) ?> +
+
+ Form->control('average_flow_rate', ['label' => __('Portata media (l/s)'), 'type' => 'number', 'min' => 0, 'disabled' => true]) ?> +
+
+
+ Form->end(); ?> + +
diff --git a/idrocap_wa/templates/WaterDrawingFees/add.php b/idrocap_wa/templates/WaterDrawingFees/add.php new file mode 100644 index 0000000..9b91c12 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/add.php @@ -0,0 +1,46 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Dettagli pratica d\'attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi Canone annuale'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingFee, ['role' => 'form']); ?> +
+
+
+ Form->control('amount', ['label' => __('Canone'), 'required' => true, 'min' => 0]); ?> +
+
+ Form->control('year', ['label' => __('Anno'), 'type' => 'number', 'min' => 1900, 'max' => ((new \DateTime())->format("Y") + 1)]); ?> + Form->hidden('water_drawing_paperwork_id', ['value' => $water_drawing_paperwork_id]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingFees/edit.php b/idrocap_wa/templates/WaterDrawingFees/edit.php new file mode 100644 index 0000000..f7eeb8d --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/edit.php @@ -0,0 +1,46 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Dettagli pratica d\'attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica Canone annuale'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingFee, ['role' => 'form']); ?> +
+
+
+ Form->control('amount', ['label' => __('Canone'), 'required' => true, 'min' => 0]); ?> +
+
+ Form->control('year', ['label' => __('Anno'), 'type' => 'number', 'min' => 1900, 'max' => ((new \DateTime())->format("Y") + 1)]); ?> + Form->hidden('water_drawing_paperwork_id', ['value' => $waterDrawingFee->water_drawing_paperwork_id]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingFees/index.php b/idrocap_wa/templates/WaterDrawingFees/index.php new file mode 100644 index 0000000..e044f94 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/index.php @@ -0,0 +1,76 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Lista canoni annuali'), + 'icon' => 'fa fa-list', + ], +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_fees ? __('{0} su {1}', $filtered_water_drawing_fees, $total_water_drawing_fees) : $total_water_drawing_fees) ?> +

+ Html->link(__('Esporta lista (CSV)'), ['action' => 'index', '_ext' => 'csv', $water_drawing_paperwork_id], ['style="margin-left:1rem;"', 'class' => 'btn btn-success btn-xs']) : null ?> +
+
+ + + + + + + + + + + + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_edit ? $this->Html->link(__('Modifica'), ['controller' => 'waterDrawingFees', 'action' => 'edit', $waterDrawingFee->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + Html->link(__('Dettagli'), ['controller' => 'waterDrawingFees', 'action' => 'view', $waterDrawingFee->id], ['class' => 'btn btn-info btn-xs'])?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingFee->id], ['confirm' => __('Sei sicuro che vuoi cancellare il canone annuale "{0}" ?', $waterDrawingFee->year), 'class' => 'btn btn-danger btn-xs']) : null; ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingFees/view.php b/idrocap_wa/templates/WaterDrawingFees/view.php new file mode 100644 index 0000000..35fc10e --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/view.php @@ -0,0 +1,91 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Dettagli pratica d\'attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli Canone annuale'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingFee, ['role' => 'form']); ?> +
+
+
+ Form->control('amount', ['label' => __('Canone'), 'required' => true, 'disabled' => true]); ?> +
+
+ Form->control('year', ['label' => __('Anno'), 'disabled' => true]); ?> + Form->hidden('water_drawing_paperwork_id', ['value' => $waterDrawingFee->water_drawing_paperwork_id]); ?> +
+
+ Form->end(); ?> +
+ +
+ +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_edit ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPayments', 'action' => 'delete', $waterDrawingPayment->id], ['confirm' => __('Sei sicuro che vuoi cancellare il pagamento n° "{0}" ?', $waterDrawingPayment->payment_number), 'class' => 'btn btn-danger btn-xs']) : null ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/add.php b/idrocap_wa/templates/WaterDrawingIntendedUses/add.php new file mode 100644 index 0000000..26ccb03 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/add.php @@ -0,0 +1,37 @@ + +
+ +
+
+ Form->create($waterDrawingIntendedUse) ?> +
+ + Form->control('area'); + echo $this->Form->control('cadastral_code'); + echo $this->Form->control('cadastral_sheet'); + echo $this->Form->control('cadastral_parcel'); + echo $this->Form->control('watering_system'); + echo $this->Form->control('consortium_area'); + echo $this->Form->control('rated_power_produced'); + echo $this->Form->control('water_drawing_paperwork_id', ['options' => $waterDrawingPaperworks]); + echo $this->Form->control('water_drawing_intended_use_type_id', ['options' => $waterDrawingIntendedUseTypes, 'empty' => true]); + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/edit.php b/idrocap_wa/templates/WaterDrawingIntendedUses/edit.php new file mode 100644 index 0000000..abbd62c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/edit.php @@ -0,0 +1,42 @@ + +
+ +
+
+ Form->create($waterDrawingIntendedUse) ?> +
+ + Form->control('area'); + echo $this->Form->control('cadastral_code'); + echo $this->Form->control('cadastral_sheet'); + echo $this->Form->control('cadastral_parcel'); + echo $this->Form->control('watering_system'); + echo $this->Form->control('consortium_area'); + echo $this->Form->control('rated_power_produced'); + echo $this->Form->control('water_drawing_paperwork_id', ['options' => $waterDrawingPaperworks]); + echo $this->Form->control('water_drawing_intended_use_type_id', ['options' => $waterDrawingIntendedUseTypes, 'empty' => true]); + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/index.php b/idrocap_wa/templates/WaterDrawingIntendedUses/index.php new file mode 100644 index 0000000..09b9ca4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/index.php @@ -0,0 +1,60 @@ + $waterDrawingIntendedUses + */ +?> +
+ Html->link(__('New Water Drawing Intended Use'), ['action' => 'add'], ['class' => 'button float-right']) ?> +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('area') ?>Paginator->sort('cadastral_code') ?>Paginator->sort('cadastral_sheet') ?>Paginator->sort('cadastral_parcel') ?>Paginator->sort('watering_system') ?>Paginator->sort('consortium_area') ?>Paginator->sort('rated_power_produced') ?>Paginator->sort('water_drawing_paperwork_id') ?>Paginator->sort('water_drawing_intended_use_type_id') ?>
Number->format($waterDrawingIntendedUse->id) ?>area) ?>cadastral_code) ?>cadastral_sheet) ?>cadastral_parcel) ?>watering_system) ?>consortium_area) ?>rated_power_produced) ?>hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_paperwork->id]) : '' ?>hasValue('water_drawing_intended_use_type') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_intended_use_type->id, ['controller' => 'WaterDrawingIntendedUseTypes', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_intended_use_type->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $waterDrawingIntendedUse->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $waterDrawingIntendedUse->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $waterDrawingIntendedUse->id], ['confirm' => __('Are you sure you want to delete # {0}?', $waterDrawingIntendedUse->id)]) ?> +
+
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?>

+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/view.php b/idrocap_wa/templates/WaterDrawingIntendedUses/view.php new file mode 100644 index 0000000..85d1f7c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/view.php @@ -0,0 +1,64 @@ + +
+ +
+
+

id) ?>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
area) ?>
cadastral_code) ?>
cadastral_sheet) ?>
cadastral_parcel) ?>
watering_system) ?>
consortium_area) ?>
rated_power_produced) ?>
hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_paperwork->id]) : '' ?>
hasValue('water_drawing_intended_use_type') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_intended_use_type->id, ['controller' => 'WaterDrawingIntendedUseTypes', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_intended_use_type->id]) : '' ?>
Number->format($waterDrawingIntendedUse->id) ?>
+
+
+
diff --git a/idrocap_wa/templates/WaterDrawingMeasurements/add.php b/idrocap_wa/templates/WaterDrawingMeasurements/add.php new file mode 100644 index 0000000..e0f8a27 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeasurements/add.php @@ -0,0 +1,51 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'] + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan', $water_drawing_paperwork_id] + ], + [ + 'title' => __('Nuova lettura dello strumento'), + 'icon' => 'fa fa-plus', + ] +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeasurement, ['role' => 'form', 'type' => 'file']); ?> +
+
+ Form->control('water_drawing_meter_id', ['type' => 'hidden', 'value' => $water_drawing_meter_id]); ?> +
+ Form->control('volume', ['label' => __('Lettura volume (m^3)'), 'type' => 'number', 'required' => true, 'min' => 0]); ?> +
+
+ Form->control('date', ['label' => __('Data del rilievo'), 'style' => 'margin-left: 5px;', 'type' => 'date', 'max' => $today->format('Y-m-d')]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingMeasurements/index.php b/idrocap_wa/templates/WaterDrawingMeasurements/index.php new file mode 100644 index 0000000..5586106 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeasurements/index.php @@ -0,0 +1,73 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'] + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id] + ], + [ + 'title' => __('Lista misurazioni relativi alla pratica'), + 'icon' => 'fa fa-list', + ], + +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_measurements ? __('{0} su {1}', $filtered_water_drawing_measurements, $total_water_drawing_measurements) : $total_water_drawing_measurements, $water_drawing_paperwork_id) ?> +

+ Html->link(__('Esporta lista (CSV)'), ['action' => 'index', '_ext' => 'csv', $water_drawing_paperwork_id], ['class' => 'btn btn-success btn-xs']) : null ?> +
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('water_drawing_meter_id', __('N° matricola strumento di misura')) ?>Paginator->sort('volume', __('Lettura volume (m^3)')) ?>Paginator->sort('date', __('Data lettura')) ?>Paginator->sort('volume', __('Utente')) ?>
water_drawing_meter->part_number) ?>volume) ?>date) ?>user) ?>
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingMeters/add.php b/idrocap_wa/templates/WaterDrawingMeters/add.php new file mode 100644 index 0000000..8315bd0 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/add.php @@ -0,0 +1,66 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi lo strumento di misura'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type_id', ['label' => __('Tipo'), 'type' => 'select', 'options' => $waterDrawingToolTypes, 'empty' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text']) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text']) ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingMeters/dismiss.php b/idrocap_wa/templates/WaterDrawingMeters/dismiss.php new file mode 100644 index 0000000..c7057cb --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/dismiss.php @@ -0,0 +1,67 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dismetti lo strumento di misura'), + 'icon' => 'fa fa-times-circle', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type.description', ['label' => __('Tipo'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text', 'disabled' => true]) ?> +
+
+
+
+ installation_date)):?> + Form->control('removal_date', ['label' => __('Data dismissione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'min' => $waterDrawingMeter->installation_date->format('Y-m-d'), 'max' => $today->format('Y-m-d')]) ?> + + Form->control('removal_date', ['label' => __('Data dismissione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> + +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingMeters/edit.php b/idrocap_wa/templates/WaterDrawingMeters/edit.php new file mode 100644 index 0000000..14302c9 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/edit.php @@ -0,0 +1,66 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica lo strumento di misura'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type_id', ['label' => __('Tipo'), 'type' => 'select', 'options' => $waterDrawingToolTypes, 'empty' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text']) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text']) ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingMeters/view.php b/idrocap_wa/templates/WaterDrawingMeters/view.php new file mode 100644 index 0000000..5aaf288 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/view.php @@ -0,0 +1,103 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettaglio dello strumento di misura'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type_id', ['label' => __('Tipo'), 'type' => 'select', 'options' => $waterDrawingToolTypes, 'empty' => true, 'disabled' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->end(); ?> +
+ +
+ +
+
+

+ +

+
+
+ + + + + + + + + + water_drawing_measurements as $waterDrawingMeasurement) : ?> + + + + + + + +
user) ?>volume) ?>date->format("d/m/Y")) ?>
+
+ +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php new file mode 100644 index 0000000..684edc2 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php @@ -0,0 +1,62 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi il documento PEC'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperworkPec, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->hidden('water_drawing_paperwork_id', ['value' => $water_drawing_paperwork_id]) ?> + Form->control('document', ['label' => __('Documento'), 'type' => 'text']) ?> + Form->control('protocol_number', ['label' => __('Numero di protocollo'), 'type' => 'text']) ?> + Form->control('recipient', ['label' => __('Destinatario'), 'type' => 'text']) ?> + Form->control('sender', ['label' => __('Inviato da'), 'type' => 'text']) ?> + Form->control('protocol_date', ['label' => __('Data'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> + element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + ?> + Form->control('note', ['label' => 'Note:', 'type' => 'textarea']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php new file mode 100644 index 0000000..6cdf4b4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php @@ -0,0 +1,62 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + //'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica il documento PEC'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperworkPec, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('document', ['label' => __('Documento'), 'type' => 'text']) ?> + Form->control('protocol_number', ['label' => __('Numero di protocollo'), 'type' => 'text']) ?> + Form->control('recipient', ['label' => __('Destinatario'), 'type' => 'text']) ?> + Form->control('sender', ['label' => __('Inviato da'), 'type' => 'text']) ?> + Form->control('protocol_date', ['label' => __('Data'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> + element('attachments', [ + 'coId' => $waterDrawingPaperworkPec->controllable_object_id, + 'filepicker' => true, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'tags' => $tags, + 'required' => false, + 'view_in_frame_with_id' => false, + 'accept_only' => ['.pdf'] + ]); + ?> + Form->control('note', ['label' => 'Note:', 'type' => 'textarea']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php new file mode 100644 index 0000000..7acbe21 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php @@ -0,0 +1,81 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'] + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id] + ], + [ + 'title' => __('Lista misurazioni relativi alla pratica'), + 'icon' => 'fa fa-list', + ], + +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_papwork_pecs ? __('{0} su {1}', $filtered_water_drawing_papwork_pecs, $total_water_drawing_papwork_pecs) : $total_water_drawing_papwork_pecs, $water_drawing_paperwork_id) ?> +

+ + Html->link(__('Aggiungi documento'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'add', $water_drawing_paperwork_id], ['class' => 'btn btn-success btn-xs pull-right', 'style' => 'margin-right:1rem; margin-bottom:1rem;']); ?> + +
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('document', __('Documento')) ?>Paginator->sort('protocol_number', __('Numero protocollo')) ?>Paginator->sort('protocol_date', __('Data')) ?>Paginator->sort('user_id', __('Utente')) ?>
document) ?>protocol_number) ?>protocol_date) ?>user) ?> + can_edit_pec ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']) : null; ?> + Html->link(__('Visualizza'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']); ?> + can_delete_pec ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete', $waterDrawingPaperworkPec->id], ['confirm' => __('Sei sicuro che vuoi cancellare la documentazione PEC "{0}" ?', $waterDrawingPaperworkPec->id), 'class' => 'btn btn-danger btn-xs', 'style' => 'margin-right:1rem']) : null; ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php new file mode 100644 index 0000000..17c80dc --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php @@ -0,0 +1,61 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + //'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli documento PEC'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperworkPec, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('document', ['label' => __('Documento'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('protocol_number', ['label' => __('Numero di protocollo'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('recipient', ['label' => __('Destinatario'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('sender', ['label' => __('Inviato da'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('protocol_date', ['label' => __('Data'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> + element('attachments', [ + 'coId' => $waterDrawingPaperworkPec->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'tags' => $tags, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => false, + ]); + ?> + Form->control('note', ['label' => 'Note:', 'type' => 'textarea', 'disabled' => true]); + ?> + Form->end(); ?> +
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/add.php b/idrocap_wa/templates/WaterDrawingPaperworks/add.php new file mode 100644 index 0000000..f27d3aa --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/add.php @@ -0,0 +1,632 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Gestione Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], +]); +?> +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+
+
+

+ +

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file', 'id' => 'editWaterDrawingPaperwork']); ?> +
+ +
+
+

+ +

+
+ +
+
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'required' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), "style" => "cursor: not-allowed", 'type' => 'text', "disabled" => true, 'value' => (isset($hide_authority_province) && $hide_authority_province) ? ($authority_civil_engineer_code ?? null) : null]) ?> +
+ + Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, autoFillTargetId: "authority-civil-engineer-code", autoFillTargetEnabled: true, fieldRequired: true, showProvinceFullName: true)]) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}']) ?> +
+
+ Form->control('protocol_number', ['label' => __('Numero di protocollo della pratica'), 'type' => 'text']) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'empty' => true, 'options' => $WaterDrawingArticles]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, "formContext" => $waterDrawingPaperwork]); + ?> +
+
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+
+ Cell('IntendedUses', ['intended_use_item_block' => 0]); + ?> +
+
+
+
+
+ +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date']) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text']) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text']) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)')]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'max' => $today->format('Y-m-d')]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)')]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text']) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+
+
+ +
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php new file mode 100644 index 0000000..1c9660a --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Nuova Pratica di attingimento Scansionata'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('water_drawing_paperwork_status_id', ['type' => 'hidden', 'value' => 1]); + echo $this->element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'required' => false, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php b/idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php new file mode 100644 index 0000000..867f848 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica ricevuta della richiesta antimafia alla Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php b/idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php new file mode 100644 index 0000000..093a6fe --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php @@ -0,0 +1,5 @@ +element('WaterDrawingPaperworks/applicants', [ + 'applicant_item_block' => $applicant_item_block, + 'water_drawing_paperwork_status_id' => isset($waterDrawingPaperwork) ? $waterDrawingPaperwork->water_drawing_paperwork_status_id : null, + 'water_drawing_paperwork_id' => isset($waterDrawingPaperwork) ? $waterDrawingPaperwork->id : null +]);?> \ No newline at end of file diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/assign.php b/idrocap_wa/templates/WaterDrawingPaperworks/assign.php new file mode 100644 index 0000000..8d89319 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/assign.php @@ -0,0 +1,48 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Assegna Pratica di attingimento'), + 'icon' => 'fa fa-user', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control(($organisation_type_id == 6 ? 'drar_user_id' : 'gc_user_id'), ['id' => 'select2user-id', 'label' => __('Ricerca utente'), 'type' => 'select', 'options' => $users, 'empty' => true, 'required' => true]); ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php new file mode 100644 index 0000000..65fd6c5 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php @@ -0,0 +1,115 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista documenti della richiesta di attingimento'), + 'icon' => 'fa fa-list', + ], +]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('original_file_name', __('Nome del file')) ?>Paginator->sort('mimetype', __('Tipologia file')) ?>Paginator->sort('description', __('Tipologia documento')) ?>Paginator->sort('upload_date', __('Caricato il')) ?>
original_file_name) ?>mimetype) ?>tags[0]->description) ?>upload_date) ?> + Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', $attachment->file_name], ['class' => 'btn btn-info btn-xs', 'target' => '_blank']) ?> + water_drawing_paperwork_status_id == 8 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 11) ? $this->Html->link(__('Elimina'), ['action' => 'delete_attachment', $waterDrawingPaperwork->id, $attachment->id], ['class' => 'btn btn-warning btn-xs', 'confirm' => __('Sei sicuro di voler cancellare questo documento?')]) : ''?> +
+
+
+ water_drawing_paperwork_status_id == 8 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 11 ? $this->Html->link(__('Aggiungi documentazione'), ['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id], ['class' => 'btn btn-success btn-xs']) : '' ?> + is_citizen_water_drawing_paperwork_ok_to_send() ? $this->Html->link(__('Invia richiesta'), ['action' => 'citizen_send_to_validation', $waterDrawingPaperwork->id], ['confirm' => __('Vuoi procedere con l\'invio ?'), 'class' => 'btn btn-info btn-xs']) : ''?> +
+ +
+ +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php new file mode 100644 index 0000000..30451d0 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php @@ -0,0 +1,376 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista Documenti sottomessi della Pratica'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Lista modulistica'), + 'icon' => 'fa fa-list', + ], +]); +?> + +
+
+

+ +

+
+
+
+
+

+ +

+
+
+
+
+ +
+
+ check_adam) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 5], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 5], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+

+ +

+
+
+
+
+ +
+
+ check_rap) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 1], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 1], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_ia7) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 2], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 2], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_ia56) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 3], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 3], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_isu) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 6], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 6], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+ +
+ +
+
+ check_ira) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 4], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 4], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_irc56) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 20], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 20], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+

+ +

+
+
+
+
+ +
+
+ check_thc_a) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 7], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 7], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_aa) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 8], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 8], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ab) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 9], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 9], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ac) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 10], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 10], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ad) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 11], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 11], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ae) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 12], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 12], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_af) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 13], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 13], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ag) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 14], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 14], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b1) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 16], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 16], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b2) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 17], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 17], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b3) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 18], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 18], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b4) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 19], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 19], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_rpdi) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_payment_receipt', $waterDrawingPaperwork->id, -15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Carica ricevuta'), ['action' => 'citizen_upload_payment_receipt', $waterDrawingPaperwork->id, -15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php new file mode 100644 index 0000000..e183541 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php @@ -0,0 +1,35 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Carica allegato'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+
+ Html->link(__('Per mio conto'), ['controller' => 'Applicants', 'action' => 'citizen_view'], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + echo '

Per conto terzi

'; + ?> +
+
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php new file mode 100644 index 0000000..b106d06 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php @@ -0,0 +1,73 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + ], +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_paperworks ? __('{0} su {1}', $filtered_water_drawing_paperworks, $total_water_drawing_paperworks) : $total_water_drawing_paperworks) ?> +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id', __('ID')) ?>Paginator->sort('authority_identification_code_civil_engineering_office', __('Codice identificativo')) ?>Paginator->sort('WaterDrawingPaperworkStatuses.description', __('Stato')) ?>Paginator->sort('authority_province', __('Provincia')) ?>Paginator->sort('release_date', __('Data di rilascio')) ?>Paginator->sort('expiration_date', __('Scadenza')) ?>Paginator->sort('ControllableObjects.created', __('Creata il')) ?>Paginator->sort('ControllableObjects.modified', __('Modificata il')) ?>
Number->format($waterDrawingPaperwork->id) ?>authority_identification_code_civil_engineering_office) ?>water_drawing_paperwork_status->rgb) ? 'style="color:' . $waterDrawingPaperwork->water_drawing_paperwork_status->rgb . '"' : '' ?>>water_drawing_paperwork_status->description) ?>authority_province) ?>release_date) ?>expiration_date) ?>controllable_object->created) ?>controllable_object->modified) ?> + Html->link(__('Dettaglio'), ['action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], ['class' => 'btn btn-info btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php new file mode 100644 index 0000000..154293e --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php @@ -0,0 +1,46 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Selezione della provincia di competenza'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $applicant, autoFillTargetEnabled: false, fieldRequired: true, showProvinceFullName: true)]) ?> +
+ + + +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php new file mode 100644 index 0000000..ce7febd --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php @@ -0,0 +1,60 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista documenti della richiesta di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Carica allegato'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ link != '') { + echo $this->Html->link($tag->description, ['controller' => 'Attachments', 'action' => 'view', $tag->link], ['target' => '_blank']); + echo $this->Html->link(__('Scarica'), ['controller' => 'Attachments', 'action' => 'view', $tag->link], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm', 'target' => '_blank']); + } + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => [ + $tag->code => $tag->description, + ], + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.p7m'] + ]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php new file mode 100644 index 0000000..a73695f --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php @@ -0,0 +1,58 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista documenti della richiesta di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Carica allegato'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

id) ?>

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ Html->link(__('Portale pagamenti - Regione Siciliana'), 'https://pagamenti.regione.sicilia.it/static/', ['target' => '_blank']); + echo $this->Html->link(__('Accedi al portale'), 'https://pagamenti.regione.sicilia.it/static/', ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm', 'target' => '_blank']); + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => [ + $tag->code => $tag->description, + ], + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/edit.php b/idrocap_wa/templates/WaterDrawingPaperworks/edit.php new file mode 100644 index 0000000..119f9dd --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/edit.php @@ -0,0 +1,641 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Pratica di attingimento'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+ +
+
+

+ +

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file', 'id' => 'editWaterDrawingPaperwork']); ?> +
+ +
+
+

+ +

+
+ +
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => true, + 'tags' => $tags_picker, + 'required' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); + + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'view_in_frame_with_id' => 'previewiframe', + 'tags' => $tags_viewer, + 'required' => false + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), "style" => "cursor: not-allowed", 'type' => 'text', "disabled" => true, 'value' => (isset($hide_authority_province) && $hide_authority_province) ? ($authority_civil_engineer_code ?? null) : null]) ?> +
+ + Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, autoFillTargetId: "authority-civil-engineer-code", autoFillTargetEnabled: true, fieldRequired: true, showProvinceFullName: true)]) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}']) ?> +
+
+ Form->control('protocol_number', ['label' => __('Numero di protocollo della pratica'), 'type' => 'text']) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'empty' => true, 'options' => $waterDrawingArticles]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'applicant' => $applicant, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses) == 0) echo $this->Cell('IntendedUses', ['intended_use_item_block' => 0]); + foreach ($waterDrawingPaperwork->water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date']) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text']) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text']) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)')]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'max' => $today->format('Y-m-d')]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)')]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text']) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+
+
+ +
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php new file mode 100644 index 0000000..9eff8e2 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php @@ -0,0 +1,667 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Pratica di attingimento scansionata'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+ +
+
+

+ +

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file', 'id' => 'editWaterDrawingPaperwork']); ?> +
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status_id', ['type' => 'hidden', 'value' => $waterDrawingPaperwork->water_drawing_paperwork_status_id >= 6 ? $waterDrawingPaperwork->water_drawing_paperwork_status_id : ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 4 ? 5 : 3)]); + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => true, + 'tags' => $tags_picker, + 'required' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); + + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'view_in_frame_with_id' => 'previewiframe', + 'tags' => $tags_viewer, + 'required' => false + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), "style" => "cursor: not-allowed", 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), "disabled" => true]) ?> +
+ Cell( + "DistrictProvince", + [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + autoFillTargetId: "authority-civil-engineer-code", + autoFillTargetEnabled: true, + fieldRequired: true, + fieldType: ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? InputFieldType::SELECT : InputFieldType::HIDDEN), + showProvinceFullName: true + ) + ] + ) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text']) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'select' : 'hidden'), 'options' => $waterDrawingArticles]) ?> +
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'applicant' => $applicant, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+ +
+
+
+ + water_drawing_paperwork_status_id > 3) : ?> +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses) == 0) echo $this->Cell('IntendedUses', ['intended_use_item_block' => 0]); + foreach ($waterDrawingPaperwork->water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+ +
+
+
+ + + water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date']) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date']) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)')]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'style' => 'margin-left: 5px;']) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'number' : 'hidden'), 'pattern' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? '[0-9]*' : '')]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'style' => 'margin-left: 5px;']) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+
+
+ + water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+
+
+ +
+ + + +
+ + +water_drawing_paperwork_status_id === 1): ?> + + Html->script('ia-form-filler/dist/entrypoints/content.js', ['type' => 'module']) ?> + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/index.php b/idrocap_wa/templates/WaterDrawingPaperworks/index.php new file mode 100644 index 0000000..d0a942c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/index.php @@ -0,0 +1,81 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_paperworks ? __('{0} su {1}', $filtered_water_drawing_paperworks, $total_water_drawing_paperworks) : $total_water_drawing_paperworks) ?> +

+ Html->link(__('Esporta CSV'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_csv'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> + Html->link(__('Estrai pagamenti'), ['controller' => 'WaterDrawingPayments', 'action' => 'index_all', '_ext' => 'csv'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> + Html->link(__('Visualizza Logs'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id', __('ID')) ?>Paginator->sort('authority_identification_code_civil_engineering_office', __('Codice identificativo')) ?>Paginator->sort('WaterDrawingPaperworkStatuses.description', __('Stato')) ?>Paginator->sort('authority_province', __('Provincia')) ?>Paginator->sort('release_date', __('Data di rilascio')) ?>Paginator->sort('expiration_date', __('Scadenza')) ?>Paginator->sort('ControllableObjects.created', __('Creata il')) ?>Paginator->sort('ControllableObjects.modified', __('Modificata il')) ?>
Number->format($waterDrawingPaperwork->id) ?>authority_identification_code_civil_engineering_office) ?>water_drawing_paperwork_status->rgb) ? 'style="color:'. $waterDrawingPaperwork->water_drawing_paperwork_status->rgb . '"' : '' ?>>water_drawing_paperwork_status->description) ?>authority_province) ?>release_date) ?>expiration_date) ?>percentage) ?>controllable_object->created) ?>controllable_object->modified) ?> + Html->link(__('Dettaglio'), ['action' => ($waterDrawingPaperwork->scanned ? 'view_scan' : 'view'), $waterDrawingPaperwork->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => ($waterDrawingPaperwork->scanned ? 'edit_scan' : 'edit'), $waterDrawingPaperwork->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro che vuoi cancellare la pratica di attingimento con ID:"{0}" ?', $waterDrawingPaperwork->id), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php new file mode 100644 index 0000000..ee61e92 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php @@ -0,0 +1,80 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Storico Pratica di attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+ Html->link(__('Esporta CSV'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_csv', $water_drawing_paperwork_id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('when', __('Data')) ?>Paginator->sort('who', __('Da')) ?>Paginator->sort('what', __('Azione')) ?>Paginator->sort('water_drawing_paperwork_status', __('Stato Pratica')) ?>Paginator->sort('gc_user', __('Assegnatario Genio Civile')) ?>Paginator->sort('drar_user', __('Assegnatario DRAR')) ?>
when) ? (new DateTime($unpackedWaterDrawingPaperworkSnapshot->when))->i18nFormat('dd/MM/Y HH:mm:ss', $logged_user_timezone) : null) ?>who) ?>what) ?>water_drawing_paperwork_status) ?>gc_user) ?>drar_user) ?> + Html->link(__('Dettaglio'), ['action' => ($waterDrawingPaperwork->scanned ? 'view_scan_snapshot' : 'view_snapshot'), $unpackedWaterDrawingPaperworkSnapshot->snapshot_id], ['class'=>'btn btn-info btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php new file mode 100644 index 0000000..deadc64 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php @@ -0,0 +1,77 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Logs Pratiche di attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+ Html->link(__('Esporta CSV'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all_csv'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('when', __('Data')) ?>Paginator->sort('who', __('Da')) ?>Paginator->sort('what', __('Azione')) ?>Paginator->sort('water_drawing_paperwork_id', __('ID Pratica')) ?>Paginator->sort('water_drawing_paperwork_status', __('Stato Pratica')) ?>Paginator->sort('gc_user', __('Assegnatario Genio Civile')) ?>Paginator->sort('drar_user', __('Assegnatario DRAR')) ?>
when) ? (new DateTime($unpackedWaterDrawingPaperworkSnapshot->when))->i18nFormat('dd/MM/Y HH:mm:ss', $logged_user_timezone) : null) ?>who) ?>what) ?>water_drawing_paperwork_id) ?>water_drawing_paperwork_status) ?>gc_user) ?>drar_user) ?> + Html->link(__('Dettaglio'), ['action' => 'view_snapshot', $unpackedWaterDrawingPaperworkSnapshot->snapshot_id, '?' => ['origin' => 'logs']], ['class'=>'btn btn-info btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php b/idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php new file mode 100644 index 0000000..316ef1b --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php @@ -0,0 +1 @@ +Cell('IntendedUses', ['intended_use_item_block' => ($intended_use_item_block)]);?> \ No newline at end of file diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php b/idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php new file mode 100644 index 0000000..fe9e69b --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica antimafia alla Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php new file mode 100644 index 0000000..8720542 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php @@ -0,0 +1,50 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica allegato Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php new file mode 100644 index 0000000..f8ee0b4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php @@ -0,0 +1,50 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica allegato Pratica di attingimento scansionata'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('water_drawing_paperwork_status_id', ['type' => 'hidden', 'value' => 1]); + echo $this->element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/validate.php b/idrocap_wa/templates/WaterDrawingPaperworks/validate.php new file mode 100644 index 0000000..146fdae --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/validate.php @@ -0,0 +1,713 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Validazione Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+
+
+ +
+ +
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> + Form->control('gc_user', ['label' => __('Assegnatario Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('drar_user', ['label' => __('Assegnatario DRAR'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ')?>check_dv ? __('Presente') : __('Assente ')?>check_lic ? __('Presente') : __('Assente ')?>check_dec ? __('Presente') : __('Assente ')?>check_sdd ? __('Presente') : __('Assente ')?>check_dsc ? __('Presente') : __('Assente ')?>check2a ? __('Presente') : __('Assente ')?>check_dam ? __('Presente') : __('Assente ')?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + 'tags' => null + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, fieldRequired: true, disabled: true, showProvinceFullName: true)]) ?> +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true, 'disabled' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'options' => $WaterDrawingArticles, 'empty' => true, 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude . ', ' . $waterDrawingDerivation->longitude) ?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'disabled' => true]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'disabled' => true]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'disabled' => true]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= -4) : ?> + + +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:0.5rem']); + } + ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_antimafia_certification_requests as $waterDrawinAntimafiaRequest) : ?> + + + + + + + +
user) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>water_drawing_antimafia_certification_request_status->description) . ($waterDrawinAntimafiaRequest->water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? __(' - Richiesta scaduta') : null) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>created) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + water_drawing_paperwork_pecs as $waterDrawingPaperworkPec) : ?> + + + + + + + + +
document) ?>protocol_number) ?>protocol_date->format('d/m/Y')) ?> + Html->link(__('Visualizza'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']); ?> +
+
+ +
+Form->end() ?> +
+
+

+ +

+ +
+
+ Form->create($waterDrawingPaperworkHistory, ['role' => 'form', 'type' => 'file']); ?> +
+
+ Form->hidden('water_drawing_paperwork_status_id', ['value' => $waterDrawingPaperwork->water_drawing_paperwork_status_id]); + echo $this->Form->control('result', ['label' => __('Esito'), 'onChange' => 'checkNote()', 'type' => 'radio', 'options' => [1 => __('Accettata'), 0 => __('Respinta')]]); + ?> +
+
+ + Form->control('note', ['label' => false, 'type' => 'textarea', 'id' => 'note-field']); + ?> +
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'upload_single' => true, + 'required' => false, + 'accept_only' => ['.pdf'] + ]); + ?> +
+
+ Form->submit(__('Salva')); ?> +
+
+ Form->end(); ?> +
+ +
+ + + + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php b/idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php new file mode 100644 index 0000000..0853e7b --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php @@ -0,0 +1,71 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento da validare'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id', __('ID')) ?>Paginator->sort('WaterDrawingPaperworkStatuses.description', __('Stato')) ?>Paginator->sort('district', __('Comune')) ?>Paginator->sort('release_date', __('Data di rilascio')) ?>Paginator->sort('concession_duration', __('Durata della Derivazione (anni)')) ?>Paginator->sort('expiration_date', __('Scadenza')) ?>Paginator->sort('ControllableObjects.created', __('Creata il')) ?>Paginator->sort('ControllableObjects.modified', __('Modificata il')) ?>
Number->format($waterDrawingPaperwork->id) ?>water_drawing_paperwork_status->description) ?>district) ?>release_date) ?>concession_duration) ? $this->Number->format($waterDrawingPaperwork->concession_duration) : '' ?>expiration_date) ?>controllable_object->created) ?>controllable_object->modified) ?> + can_validate ? $this->Html->link(__('Valida'), ['controller' => 'WaterDrawingPaperworks', 'action' => ( $waterDrawingPaperwork->scanned ? 'validate_scan' : 'validate'), $waterDrawingPaperwork->id], ['class'=>'btn btn-info btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php new file mode 100644 index 0000000..a8764c7 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php @@ -0,0 +1,728 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento scansionata'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ +
+ + + water_drawing_paperwork_status_id > 5): ?> + + water_drawing_paperwork_status_id > 3): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + +
+
+
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (((($logged_user_id === $waterDrawingPaperwork->gc_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < 0) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dam ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_upload_antimafia_attachment) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + fieldRequired: true, + disabled: true, + fieldType: ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? InputFieldType::SELECT : InputFieldType::HIDDEN), + showProvinceFullName: true + ) + ] + ) ?> +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'select' : 'hidden'), 'options' => $waterDrawingArticles, 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +water_drawing_paperwork_status_id > 5): ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude . ', ' . $waterDrawingDerivation->longitude) ?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 3) : ?> +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes]); + } + ?> +
+
+
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'number' : 'hidden'), 'pattern' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? '[0-9]*' : ''), 'disabled' => true]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+
+
+ +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingFees', 'action' => 'edit', $waterDrawingFees->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= -4) : ?> + + +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs']); + echo $this->Html->link(__('Dismetti'), ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-danger btn-xs']); + } else { + echo $this->Html->link(__('Aggiungi strumento di misura'), ['controller' => 'WaterDrawingMeters', 'action' => 'add', $waterDrawingIntendedUse->id], ['class' => 'btn btn-success btn-xs']); + } + ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('user_id', __('Utente')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+Form->end(); +echo $this->Form->create($waterDrawingPaperworkHistory, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); +?> + +
+
+

+
+
+
+
+ Form->control('result', ['label' => __('Esito'), 'onChange' => 'checkNote()', 'type' => 'radio', 'options' => [1 => __('Accettata'), 0 => __('Respinta')]]); ?> +
+
+ Form->control('note', ['label' => __('Note'), 'type' => 'textarea']); ?> +
+
+
+ + + Form->end() ?> + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/view.php b/idrocap_wa/templates/WaterDrawingPaperworks/view.php new file mode 100644 index 0000000..93e5af4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/view.php @@ -0,0 +1,768 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+
+
+
+
+ +
+
+
+
+ + + + + + + + can_view_fee && $waterDrawingPaperwork->can_view_payment): ?> + + + + + + + +
+
+
+
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> + Form->control('gc_user', ['label' => __('Assegnatario Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('drar_user', ['label' => __('Assegnatario DRAR'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (((($logged_user_id === $waterDrawingPaperwork->gc_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < 0) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_ram ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_antimafia_request_to_anac) ? $this->Html->link(__('Carica'), ['action' => 'antimafia_request_to_anac', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_adam || $waterDrawingPaperwork->check_dam) ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_upload_antimafia_attachment) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, fieldRequired: true, disabled: true, showProvinceFullName: true)]) ?> +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true, 'disabled' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'disabled' => true]) ?> +
+
+ Form->control('protocol_number', ['label' => __('Numero di protocollo della pratica'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'options' => $WaterDrawingArticles, 'empty' => true, 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude, $waterDrawingDerivation->longitude) ? (number_format((float) $waterDrawingDerivation->latitude, 4) . ', ' . number_format((float) $waterDrawingDerivation->longitude, 4)) : '')?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude, $waterDrawingDerivation->longitude) ? (number_format((float) $waterDrawingDerivation->latitude, 4) . ', ' . number_format((float) $waterDrawingDerivation->longitude, 4)) : '')?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'disabled' => true]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'disabled' => true]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'disabled' => true]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+
+
+
+can_view_fee && $waterDrawingPaperwork->can_view_payment): ?> +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?>paied ? 'SI' : 'NO') ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingFees', 'action' => 'edit', $waterDrawingFees->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>applicant_tax_code) ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> + can_delete_payment ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPayments', 'action' => 'delete', $waterDrawingPayment->id], ['confirm' => __('Sei sicuro che vuoi cancellare il pagamento n° "{0}" ?', $waterDrawingPayment->payment_number), 'class' => 'btn btn-danger btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= -4) : ?> + + +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date?->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:0.5rem']); + echo $this->Html->link(__('Dismetti'), ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-danger btn-xs']); + } else { + echo $this->Html->link(__('Aggiungi strumento di misura'), ['controller' => 'WaterDrawingMeters', 'action' => 'add', $waterDrawingIntendedUse->id], ['class' => 'btn btn-success btn-xs', 'style' => 'margin-right:1rem']); + } + ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_antimafia_certification_requests as $waterDrawinAntimafiaRequest) : ?> + + + + + + + +
user) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>water_drawing_antimafia_certification_request_status->description) . ($waterDrawinAntimafiaRequest->water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? __(' - Richiesta scaduta') : null) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>created) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + water_drawing_paperwork_pecs as $waterDrawingPaperworkPec) : ?> + + + + + + + + +
document) ?>protocol_number) ?>protocol_date->format('d/m/Y')) ?> + can_edit_pec ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']) : null; ?> + Html->link(__('Visualizza'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']); ?> + can_delete_pec ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete', $waterDrawingPaperworkPec->id], ['confirm' => __('Sei sicuro che vuoi cancellare la documentazione PEC "{0}" ?', $waterDrawingPaperworkPec->id), 'class' => 'btn btn-danger btn-xs', 'style' => 'margin-right:1rem']) : null; ?> +
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('user_id', __('Utente')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+ +
+
+

+
+
+
+ can_send_to_drar ? $this->Html->link(__('Invia pratica al DRAR'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_drar', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro di inviare la pratica al DRAR?'), 'class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_send_to_gc ? $this->Html->link(__('Invia pratica al GC'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_gc', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro di inviare la pratica al Genio Civile di competenza?'), 'class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_assign_to_drar ? $this->Html->link(__('Assegna pratica DRAR'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign', $waterDrawingPaperwork->id, 6], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_assign_to_gc ? $this->Html->link(__('Assegna pratica GC'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign', $waterDrawingPaperwork->id, 0], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_validate ? $this->Html->link(__('Verifica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate', $waterDrawingPaperwork->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $waterDrawingPaperwork->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro che vuoi cancellare la pratica di attingimento "{0}" ?', $waterDrawingPaperwork->id), 'class' => 'btn btn-danger btn-xs']) : null; + ?> +
+
+
+ +Form->end() ?> + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php new file mode 100644 index 0000000..f1bacb8 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php @@ -0,0 +1,727 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento scansionata'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ +
+ + + water_drawing_paperwork_status_id > 5): ?> + + water_drawing_paperwork_status_id > 3): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + +
+
+
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dam ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + fieldRequired: true, + disabled: true, + fieldType: ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? InputFieldType::SELECT : InputFieldType::HIDDEN), + showProvinceFullName: true + ) + ] + ) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'select' : 'hidden'), 'options' => $WaterDrawingArticles, 'disabled' => true]) ?> +
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +water_drawing_paperwork_status_id > 5): ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude, $waterDrawingDerivation->longitude) ? (number_format((float) $waterDrawingDerivation->latitude, 4) . ', ' . number_format((float) $waterDrawingDerivation->longitude, 4)) : '')?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 3) : ?> +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): + ?> +
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> +
+ +
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'pattern' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? '[0-9]*' : ''), 'disabled' => true]) ?> +
+ +
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): + ?> +
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+ +
+
+
+ +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingFees', 'action' => 'edit', $waterDrawingFees->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= 5) : ?> + + +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date?->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs']); + echo $this->Html->link(__('Dismetti'), ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-danger btn-xs']); + } else { + echo $this->Html->link(__('Aggiungi strumento di misura'), ['controller' => 'WaterDrawingMeters', 'action' => 'add', $waterDrawingIntendedUse->id], ['class' => 'btn btn-success btn-xs']); + } + ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('user_id', __('Utente')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+ +
+
+

+
+ +
+ +Form->end() ?> + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php b/idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php new file mode 100644 index 0000000..cf408dd --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php @@ -0,0 +1,641 @@ + +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Logs Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all'], + ], + [ + 'title' => __('Dettagli Istantanea Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], + ]); +} else { + echo $this->Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan' : 'view'), $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Storico Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Dettagli Istantanea Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], + ]); +} +?> + +
+
+

i18nFormat('dd/MM/Y HH:mm:ss', $logged_user_timezone) : null)); ?>

+ Html->link('' . __('Istantanea precedente'), ['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan_snapshot' : 'view_snapshot'), $previous_snapshot_id, '?' => $back_to_logs ? ['origin' => 'logs'] : []], ['escape' => false, 'style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> + Html->link(__('Istantanea successiva') . '', ['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan_snapshot' : 'view_snapshot'), $next_snapshot_id, '?' => $back_to_logs ? ['origin' => 'logs'] : []], ['escape' => false, 'style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ +
+ +
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> + Form->control('gc_user', ['label' => __('Assegnatario Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('drar_user', ['label' => __('Assegnatario DRAR'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (((($logged_user_id === $waterDrawingPaperwork->gc_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < 0) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dam ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_upload_antimafia_attachment) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + fieldRequired: true, + disabled: true, + fieldContainerClass: "", + showProvinceFullName: true + ) + ] + ) ?> + Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true, 'disabled' => true]) ?> + Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'disabled' => true]) ?> + Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'options' => $WaterDrawingArticles, 'empty' => true, 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + +
latitude . ', ' . $waterDrawingDerivation->longitude) ?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> + Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> + Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'disabled' => true]) ?> + Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'disabled' => true]) ?> + Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'disabled' => true]) ?> + Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?>
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee_year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?>
+ +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + ?> + + + + + + + + + +
water_drawing_intended_use_type->description ?? '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> + Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> + Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> + Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_antimafia_certification_requests as $waterDrawinAntimafiaRequest) : ?> + + + + + + + +
user) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>water_drawing_antimafia_certification_request_status->description) . ($waterDrawinAntimafiaRequest->water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? __(' - Richiesta scaduta') : null) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>created) ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_paperwork_pecs as $waterDrawingPaperworkPec) : ?> + + + + + + + +
document) ?>protocol_number) ?>protocol_date) ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+ +Form->end() ?> + + + + diff --git a/idrocap_wa/templates/WaterDrawingPayments/add.php b/idrocap_wa/templates/WaterDrawingPayments/add.php new file mode 100644 index 0000000..1bf3c60 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/add.php @@ -0,0 +1,93 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Nuovo pagamento'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPayment, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_fee_id', ['label' => __('Anno'), 'options' => $waterDrawingFees, 'empty' => true, 'required' => true]);?> +
+
+ Form->control('water_drawing_payment_type_id', ['label' => __('Tipologia di pagamento'), 'empty' => true]); ?> +
+
+ Form->control('amount', ['label' => __('Importo'), 'min' => 0]); ?> +
+
+ Form->control('payment_number', ['label' => __('Numero del pagamento')]); ?> +
+
+
+
+ Form->control('receipt_number', ['label' => __('Numero quietanza')]); ?> +
+
+ Form->control('receipt_amount', ['label' => __('Importo quietanza'), 'min' => 0]); ?> +
+
+ Form->control('applicant_tax_code', ['label' => __('Codice fiscale concessionario'), 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('payment_date', ['label' => __('Data pagamento'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('receipt_date', ['label' => __('Data quietanza'), 'type' => 'date', 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('notes', ['label' => __('Note')]); ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPayments/edit.php b/idrocap_wa/templates/WaterDrawingPayments/edit.php new file mode 100644 index 0000000..250ec5e --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/edit.php @@ -0,0 +1,92 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica pagamento'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPayment, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_fee_id', ['label' => __('Anno'), 'options' => $waterDrawingFees, 'empty' => true, 'required' => true]); ?> +
+
+ Form->control('water_drawing_payment_type_id', ['label' => __('Tipologia di pagamento'), 'empty' => true]); ?> +
+
+ Form->control('amount', ['label' => __('Importo'), 'min' => 0]); ?> +
+
+ Form->control('payment_number', ['label' => __('Numero del pagamento')]); ?> +
+
+
+
+ Form->control('receipt_number', ['label' => __('Numero quietanza')]); ?> +
+
+ Form->control('receipt_amount', ['label' => __('Importo quietanza'), 'min' => 0]); ?> +
+
+ Form->control('applicant_tax_code', ['label' => __('Codice fiscale concessionario'), 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('payment_date', ['label' => __('Data pagamento'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('receipt_date', ['label' => __('Data quietanza'), 'type' => 'date', 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('notes', ['label' => __('Note')]); ?> +
+
+
+
+ +Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPayments/index.php b/idrocap_wa/templates/WaterDrawingPayments/index.php new file mode 100644 index 0000000..54e63a1 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/index.php @@ -0,0 +1,83 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Lista pagamenti'), + 'icon' => 'fa fa-list', + ], +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_payments ? __('{0} su {1}', $filtered_water_drawing_payments, $total_water_drawing_payments) : $total_water_drawing_payments, $water_drawing_paperwork_id) ?> +

+ Html->link(__('Esporta lista (CSV)'), ['controller' => 'WaterDrawingPayments', 'action' => 'index', '_ext' => 'csv', $water_drawing_paperwork_id], ['class' => 'btn btn-success btn-xs']) : null ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>applicant_tax_code) ?> + can_edit ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPayments', 'action' => 'delete', $waterDrawingPayment->id], ['confirm' => __('Sei sicuro che vuoi cancellare il pagamento n° "{0}" ?', $waterDrawingPayment->payment_number), 'class' => 'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPayments/view.php b/idrocap_wa/templates/WaterDrawingPayments/view.php new file mode 100644 index 0000000..c6a26e2 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/view.php @@ -0,0 +1,95 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli pagamento'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPayment, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_fee_id', ['label' => __('Anno'), 'options' => $waterDrawingFees, 'empty' => true, 'disabled' => true]); ?> +
+
+ Form->control('water_drawing_payment_type_id', ['label' => __('Tipologia di pagamento'), 'empty' => true, 'disabled' => true]); ?> +
+
+ Form->control('amount', ['label' => __('Importo'), 'min' => 0, 'disabled' => true]); ?> +
+
+ Form->control('payment_number', ['label' => __('Numero del pagamento'), 'disabled' => true]); ?> +
+
+
+
+ Form->control('receipt_number', ['label' => __('Numero quietanza'), 'disabled' => true]); ?> +
+
+ Form->control('receipt_amount', ['label' => __('Importo quietanza'), 'min' => 0, 'disabled' => true]); ?> +
+
+ Form->control('applicant_tax_code', ['label' => __('Codice fiscale concessionario'), 'disabled' => true]); ?> +
+
+
+
+ Form->control('payment_date', ['label' => __('Data pagamento'), 'disabled' => true]); ?> +
+
+ Form->control('receipt_date', ['label' => __('Data quietanza'), 'type' => 'date', 'disabled' => true]); ?> +
+
+
+
+ Form->control('notes', ['label' => __('Note'), 'disabled' => true]); ?> +
+
+ Form->end(); ?> +
+ +
+ + + diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/add.php b/idrocap_wa/templates/WaterDrawingReturnPoints/add.php new file mode 100644 index 0000000..a0baa52 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/add.php @@ -0,0 +1,125 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi Punto di restituzione'), + 'icon' => 'fa fa-plus', + ], +]); +?> + + +
+
+

+
+ Form->create($waterDrawingReturnPoint, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> +
+
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+ Form->end(); ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/edit.php b/idrocap_wa/templates/WaterDrawingReturnPoints/edit.php new file mode 100644 index 0000000..aff970c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/edit.php @@ -0,0 +1,124 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica Punto di restituzione'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingReturnPoint, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> +
+
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+ Form->end(); ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/index.php b/idrocap_wa/templates/WaterDrawingReturnPoints/index.php new file mode 100644 index 0000000..4a1e400 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/index.php @@ -0,0 +1,54 @@ + $waterDrawingReturnPoints + */ +?> +
+ Html->link(__('New Water Drawing Return Point'), ['action' => 'add'], ['class' => 'button float-right']) ?> +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('latitude') ?>Paginator->sort('longitude') ?>Paginator->sort('district') ?>Paginator->sort('cadastral_sheet') ?>Paginator->sort('cadastral_parcel') ?>Paginator->sort('water_drawing_paperwork_id') ?>
Number->format($waterDrawingReturnPoint->id) ?>latitude) ?>longitude) ?>district) ?>cadastral_sheet === null ? '' : $this->Number->format($waterDrawingReturnPoint->cadastral_sheet) ?>cadastral_parcel === null ? '' : $this->Number->format($waterDrawingReturnPoint->cadastral_parcel) ?>hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingReturnPoint->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $waterDrawingReturnPoint->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $waterDrawingReturnPoint->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $waterDrawingReturnPoint->id], ['confirm' => __('Are you sure you want to delete # {0}?', $waterDrawingReturnPoint->id)]) ?> +
+
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?>

+
+
diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/view.php b/idrocap_wa/templates/WaterDrawingReturnPoints/view.php new file mode 100644 index 0000000..26f6132 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/view.php @@ -0,0 +1,128 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli Punto di restituzione'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingReturnPoint, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> +
+
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => false, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => false, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'disabled' => true, 'disabled' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'disabled' => true, 'disabled' => true]) ?> +
+ Form->end(); ?> +
+
+ Html->link(__('Modifica'), ['action' => 'edit', $waterDrawingReturnPoint->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']); + echo $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingReturnPoint->id], ['confirm' => __('Sei sicuro che vuoi cancellare la pratica di attingimento "{0}" ?', $waterDrawingReturnPoint->id), 'class' => 'btn btn-danger btn-xs']); + ?> +
+
+
+
+
diff --git a/idrocap_wa/templates/cell/.gitkeep b/idrocap_wa/templates/cell/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/idrocap_wa/templates/cell/.gitkeep @@ -0,0 +1 @@ + diff --git a/idrocap_wa/templates/cell/DistrictProvince/display.php b/idrocap_wa/templates/cell/DistrictProvince/display.php new file mode 100644 index 0000000..2388116 --- /dev/null +++ b/idrocap_wa/templates/cell/DistrictProvince/display.php @@ -0,0 +1,41 @@ + + + + +
+ element("provinceSelect", [ + 'provinceConfig' => $provinceCellConfig, + "provinces" => $provinces['options'] ?? null + ]) ?> +
+ + + +
+ element("districtSelect", [ + 'districtConfig' => $districtCellConfig, + "codReg" => $codReg, + "provinces" => isset($provinces) && is_array($provinces) ? $provinces['map'] : null + ]) ?> +
+ diff --git a/idrocap_wa/templates/cell/FilterInput/display.php b/idrocap_wa/templates/cell/FilterInput/display.php new file mode 100644 index 0000000..cf532dd --- /dev/null +++ b/idrocap_wa/templates/cell/FilterInput/display.php @@ -0,0 +1,12 @@ +
+
+
+ Form->control('filters[' . $name . '][]', ['label' => $label, 'type' => $type, 'options' => $options, 'value' => $value, 'class' => "form-control$additional_classes"]); + ?> +
+
+ +
+
+
diff --git a/idrocap_wa/templates/cell/Filters/display.php b/idrocap_wa/templates/cell/Filters/display.php new file mode 100755 index 0000000..d06a21a --- /dev/null +++ b/idrocap_wa/templates/cell/Filters/display.php @@ -0,0 +1,152 @@ +
+
+

+ + +

+
+ +
+
+ + +
+Html->script('moment'); ?> +Html->script('jixel-primitives'); ?> + diff --git a/idrocap_wa/templates/cell/IntendedUses/display.php b/idrocap_wa/templates/cell/IntendedUses/display.php new file mode 100644 index 0000000..8a7f713 --- /dev/null +++ b/idrocap_wa/templates/cell/IntendedUses/display.php @@ -0,0 +1 @@ +Element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $intended_use_item_block, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); ?> diff --git a/idrocap_wa/templates/cell/Map/display.php b/idrocap_wa/templates/cell/Map/display.php new file mode 100755 index 0000000..bd4e174 --- /dev/null +++ b/idrocap_wa/templates/cell/Map/display.php @@ -0,0 +1,13 @@ +Element('Map', ['layers' => $layers, 'get_current_position' => $get_current_position, 'tools' => $tools, 'drawing_layer_name' => $drawing_layer_name, 'geocoding' => $geocoding, 'point' => $point, 'multiple_points' => $multiple_points, 'polygon' => $polygon, 'circle' => $circle, 'delete_geometry' => $delete_geometry, 'feature_collection_id' => $feature_collection['id'] ?? 'feature-collection', 'longitude_id' => $longitude['id'] ?? 'longitude', 'latitude_id' => $latitude['id'] ?? 'latitude', 'coordinates_id' => $coordinates['id'] ?? 'coordinates', 'cap_id' => $cap['id'] ?? 'cap', 'province_id' => $province['id'] ?? 'province', 'district_code_id' => $district_code['id'] ?? 'district-code', 'district_id' => $district['id'] ?? 'district', 'address_id' => $address['id'] ?? 'address', 'description_id' => $description['id'] ?? 'description', 'geo_resources' => $geo_resources]); + if ($feature_collection !== false && isset($feature_collection['render']) && $feature_collection['render'] === true) echo $this->Form->control($feature_collection['name'] ?? 'feature_collection', ['id' => $feature_collection['id'] ?? 'feature-collection', 'type' => isset($feature_collection['hidden']) && $feature_collection['hidden'] === true ? 'hidden' : 'text', 'label' => $feature_collection['label'] ?? null, 'readonly' => isset($feature_collection['readonly']) && $feature_collection['readonly'] === true]); + if ($longitude !== false && isset($longitude['render']) && $longitude['render'] === true) echo $this->Form->control($longitude['name'] ?? 'longitude', ['id' => $longitude['id'] ?? 'longitude', 'type' => isset($longitude['hidden']) && $longitude['hidden'] === true ? 'hidden' : 'text', 'label' => $longitude['label'] ?? null, 'readonly' => isset($longitude['readonly']) && $longitude['readonly'] === true]); + if ($latitude !== false && isset($latitude['render']) && $latitude['render'] === true) echo $this->Form->control($latitude['name'] ?? 'latitude', ['id' => $latitude['id'] ?? 'latitude', 'type' => isset($latitude['hidden']) && $latitude['hidden'] === true ? 'hidden' : 'text', 'label' => $latitude['label'] ?? null, 'readonly' => isset($latitude['readonly']) && $latitude['readonly'] === true]); + if ($coordinates !== false && isset($coordinates['render']) && $coordinates['render'] === true) echo $this->Form->control($coordinates['name'] ?? 'coordinates', ['id' => $coordinates['id'] ?? 'coordinates', 'type' => isset($coordinates['hidden']) && $coordinates['hidden'] === true ? 'hidden' : 'text', 'label' => $coordinates['label'] ?? null, 'readonly' => isset($coordinates['readonly']) && $coordinates['readonly'] === true]); + if ($cap !== false && isset($cap['render']) && $cap['render'] === true) echo $this->Form->control($cap['name'] ?? 'cap', ['id' => $cap['id'] ?? 'cap', 'type' => isset($cap['hidden']) && $cap['hidden'] === true ? 'hidden' : 'text', 'label' => $cap['label'] ?? null, 'readonly' => isset($cap['readonly']) && $cap['readonly'] === true]); + if ($province !== false && isset($province['render']) && $province['render'] === true) echo $this->Form->control($province['name'] ?? 'province', ['id' => $province['id'] ?? 'province', 'type' => isset($province['hidden']) && $province['hidden'] === true ? 'hidden' : 'text', 'label' => $province['label'] ?? null, 'readonly' => isset($province['readonly']) && $province['readonly'] === true]); + if ($district_code !== false && isset($district_code['render']) && $district_code['render'] === true) echo $this->Form->control($district_code['name'] ?? 'district_code', ['id' => $district_code['id'] ?? 'district-code', 'type' => isset($district_code['hidden']) && $district_code['hidden'] === true ? 'hidden' : 'text', 'label' => $district_code['label'] ?? null, 'readonly' => isset($district_code['readonly']) && $district_code['readonly'] === true]); + if ($district !== false && isset($district['render']) && $district['render'] === true) echo $this->Form->control($district['name'] ?? 'district', ['id' => $district['id'] ?? 'district', 'type' => isset($district['hidden']) && $district['hidden'] === true ? 'hidden' : 'text', 'label' => $district['label'] ?? null, 'readonly' => isset($district['readonly']) && $district['readonly'] === true]); + if ($address !== false && isset($address['render']) && $address['render'] === true) echo $this->Form->control($address['name'] ?? 'address', ['id' => $address['id'] ?? 'address', 'type' => isset($address['hidden']) && $address['hidden'] === true ? 'hidden' : 'text', 'label' => $address['label'] ?? null, 'readonly' => isset($address['readonly']) && $address['readonly'] === true]); + if ($description !== false && isset($description['render']) && $description['render'] === true) echo $this->Form->control($description['name'] ?? 'description', ['id' => $description['id'] ?? 'description', 'type' => isset($description['hidden']) && $description['hidden'] === true ? 'hidden' : 'text', 'label' => $description['label'] ?? null, 'readonly' => isset($description['readonly']) && $description['readonly'] === true]); +?> \ No newline at end of file diff --git a/idrocap_wa/templates/element/Map.php b/idrocap_wa/templates/element/Map.php new file mode 100755 index 0000000..da37f83 --- /dev/null +++ b/idrocap_wa/templates/element/Map.php @@ -0,0 +1,622 @@ +element('./MapCore/MapPrimitives') ?> + + diff --git a/idrocap_wa/templates/element/MapCore/MapPrimitives.php b/idrocap_wa/templates/element/MapCore/MapPrimitives.php new file mode 100644 index 0000000..42cfb31 --- /dev/null +++ b/idrocap_wa/templates/element/MapCore/MapPrimitives.php @@ -0,0 +1,373 @@ +Html->css('/node_modules/ol/ol'); ?> +Html->css('/ol-ext/ol-ext.min'); ?> +Html->css('jixel_ol'); ?> + +
+
+
+
+ +
+
+
+ +
+ + + + + + + + + + + + + + + +
+ +Html->script('/node_modules/ol/dist/ol'); ?> +Html->script('/ol-ext/ol-ext.min'); ?> +Html->script('moment'); ?> +Html->script('jixel-primitives'); ?> + diff --git a/idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php b/idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php new file mode 100644 index 0000000..bcac0ce --- /dev/null +++ b/idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php @@ -0,0 +1,196 @@ +province ?? null) : null; +$district = $applicant ? ($applicant->district ?? null) : null; +?> +
+
+
+

+
+ +
+ Form->control('select2applicants-' . $applicant_item_block, ['id' => 'select2applicants-' . $applicant_item_block, 'label' => __('Ricerca concessionario'), 'type' => 'select', 'options' => (isset($applicant) ? [$applicant->id => $applicant->tax_code . ' - ' . $applicant->name . ' ' . $applicant->surname] : []), 'empty' => true, 'style' => 'width:50%;']) ?> +
+
+ RESET +
+ + Form->hidden('applicants.' . $applicant_item_block . '.id', ['id' => 'applicants-' . $applicant_item_block . '-id', 'readonly' => true, 'disabled' => (!isset($applicant)), 'type' => 'number']) ?> + Form->hidden('applicants.' . $applicant_item_block . '._joinData.is_primary_applicant', ['value' => ($applicant_item_block == 0 ? 1 : 0)]) ?> + 5): ?> +
+ Form->hidden('applicants.' . $applicant_item_block . '.id', ['id' => 'applicants-' . $applicant_item_block . '-id', 'readonly' => true, 'disabled' => (!isset($applicant)), 'type' => 'number']) ?> + Form->hidden('applicants.' . $applicant_item_block . '._joinData.is_primary_applicant', ['value' => ($applicant_item_block == 0 ? 1 : 0)]) ?> + Form->control('applicants.' . $applicant_item_block . '.name', ['label' => __('Nome'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden'), 'required' => true]) ?> +
+ 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.surname', ['label' => __('Cognome'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden'), 'required' => true]) ?> +
+ +
+ Form->control('applicants.' . $applicant_item_block . '.tax_code', ['label' => __('Codice fiscale'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => 'text', 'required' => true]) ?> +
+ 5): + ?>
+ Form->control('applicants.' . $applicant_item_block . '.company_name', ['label' => __('Ragione sociale'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden')]) ?> +
+ +
+ Form->control('applicants.' . $applicant_item_block . '.vat_number', ['label' => __('Partita IVA'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => 'text']) ?> +
+ 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.address', ['label' => __('Indirizzo'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden'), 'required' => true]) ?> +
+ 5): + ?> + Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: 'applicants-' . $applicant_item_block . '-province', + fieldName: 'applicants.' . $applicant_item_block . '.province', + formContext: $formContext ?? null, + fieldRequired: true, + disabled: (isset($is_view) || isset($applicant->id)), + fieldType: ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? InputFieldType::SELECT : InputFieldType::HIDDEN), + fieldValue: $province + ), + new DistrictCellDto( + fieldId: 'applicants-' . $applicant_item_block . '-district', + fieldName: 'applicants.' . $applicant_item_block . '.district', + provinceFieldId: 'applicants-' . $applicant_item_block . '-province', + fieldRequired: true, + disabled: (isset($is_view) || isset($applicant->id)), + fieldType: ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? InputFieldType::SELECT : InputFieldType::HIDDEN), + fieldValue: $district, + entity: $applicant + ) + ] + ) ?> + 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.pec_address', ['label' => __('Indirizzo PEC'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden')]) ?> +
+ 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.email_address', ['label' => __('Indirizzo email'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden')]) ?> +
+ +
+ 0 && !(isset($is_view))) : ?> + + + Modifica +
+
+
+ diff --git a/idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php b/idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php new file mode 100644 index 0000000..980e8ec --- /dev/null +++ b/idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php @@ -0,0 +1,151 @@ +
+
+
+

+ water_drawing_intended_uses) && isset($waterDrawingPaperwork->water_drawing_intended_uses[$intended_use_item_block]->water_drawing_intended_use_type_id) && $waterDrawingPaperwork->water_drawing_intended_uses[$intended_use_item_block]->water_drawing_intended_use_type_id == 1) { + if ($waterDrawingPaperwork->water_drawing_intended_uses[$intended_use_item_block]->vegetation_match_status == -1) { + ?> +
+ water_drawing_intended_uses[$intended_use_item_block]->vegetation_match_status == 0) { + ?> +
+ water_drawing_intended_uses[$intended_use_item_block]->vegetation_match_status == 1) { + ?> +
+ +
+
+
+
+ Form->hidden('water_drawing_intended_uses.' . $intended_use_item_block . '.id', []) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.water_drawing_intended_use_type_id', ['id' => 'select2water-drawing-use-type-id-' . $intended_use_item_block, 'label' => __('Uso'), 'options' => $intendedUseTypes, 'empty' => true, "onChange" => "changeIntendedUseTypes($intended_use_item_block)" , 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.area', ['label' => __('Superficie da irrigare ( 00.00.00 ha )'), 'pattern' => '\d{2}([.,]\d{2}){2}', 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_code', ['label' => __('Codice comune'), 'type' => 'text', 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_sheet', ['label' => __('Foglio di mappa'), 'type' => 'text', 'disabled' => (isset($is_view)), 'type' => 'number', 'min' => 0]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_parcel', ['label' => __('Particella da irrigare'), 'type' => 'text', 'disabled' => (isset($is_view)), 'type' => 'number', 'min' => 0]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.water_drawing_watering_system_id', ['id' => 'select2watering-system-id-' . $intended_use_item_block, 'label' => __('Sistema di irrigazione'), 'options' => $wateringSystems, 'empty' => true, 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_crop_types._ids', ['id' => 'select2cadastra-crop-type-ids-' . $intended_use_item_block, 'label' => __('Tipo coltura'), 'options' => $cadastralCropTypes, 'multiple' => true, 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.consortium_area', ['label' => __('Area consortile'), 'type' => 'text', 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.rated_power_produced', ['label' => __('Potenza nominale prodotta (kW)'), 'type' => 'number', 'disabled' => (isset($is_view)), 'min' => 0]) ?> +
+
+ 0 && !(isset($is_view))) : ?> +
+
+ +
+
+ +
+ diff --git a/idrocap_wa/templates/element/attachmentPreview.php b/idrocap_wa/templates/element/attachmentPreview.php new file mode 100755 index 0000000..89af461 --- /dev/null +++ b/idrocap_wa/templates/element/attachmentPreview.php @@ -0,0 +1,41 @@ + [ + 'html' => '', + 'width' => '256px', + 'height' => '256px', + 'background' => 'url(\'/img/giphy.gif\')', + ], + 'video/mp4' => [ + 'html' => '', + 'width' => '256px', + 'height' => '256px', + 'background' => 'url(\'/img/giphy.gif\')', + ], + 'application/pdf' => [ + 'html' => '', + 'width' => '500px', + 'height' => '500px', + 'background' => 'none', + ] + ]; + + if(isset($element[$mimetype])){ + $result = $element[$mimetype]; + } + else + { + $result = ['html' => __("Anteprima non disponibile"), 'width' => '200px', 'height' => '50px', 'background' => 'none']; + } +?> +
+ diff --git a/idrocap_wa/templates/element/attachments.php b/idrocap_wa/templates/element/attachments.php new file mode 100755 index 0000000..7a9c8f2 --- /dev/null +++ b/idrocap_wa/templates/element/attachments.php @@ -0,0 +1,341 @@ + + aggiunge un prefisso a tutti gli element html e js per evitare conflitti + 'input_name_for_attachments' --------> opzionale override degli input name 'attachments' + 'input_name_for_removefiles' --------> opzionale override degli input name 'removefiles' + 'filepicker' => true/false --------> inserisce il filepicker oppure no + 'georeferenced' => true/false --------> stabilisce se ogni singolo allegato va georeferenziato oppure no. (se è true allore upload_single viene forzato anche a true!!!!!) + 'upload_single' => true/false --------> decide se l'upload è singolo o se sono consentiti upload multipli da più paths + 'accept_only' => [] --------> se si passa questo array, i tipi di files accettati saranno solo quelli specificati + 'viewer' => true/false --------> inserisce o meno il file viewer + 'coId' --------> controllable object id, necessario se la proprietà precedente 'viewer' è true + 'currentFilesRemovable' => true/false --------> decide se è possibile eliminare i files già presenti o meno + 'enableRelated' => true/false --------> visualizza anche gli allegati degli oggetti associati (esempio in un evento visualizza anche gli allegati delle observations) + 'allow_private' => true/false --------> stabilisce se devono esserci files pubblici e privati o soltanto pubblci + 'public_required' => true/false --------> setta allegato pubblico come obbligatorio oppure no + 'required' => true/false --------> setta l'allegato come obbligatorio oppure no + 'tags' => [] --------> serve a passare uno o + tags (vedi tabella Tags) per creare diverse sezioni di allegati. ogni elemento key=>value dell'array va inserito come code/description della sezione che si vuole creare. esempio: 'tags' => ['code1' => 'Allegati di tipo 1', 'code2' => 'Allegati di tipo 2', 'code3' => 'Allegati di tipo 3'] + 'view_in_frame_with_id' --------> se settato, viene effettuato il rendering dell'allegato all'interno deill'iframe con id specificato + */ + + $prefix = isset($prefix) && is_string($prefix) ? $prefix : ''; + $input_name_for_attachments = isset($input_name_for_attachments) && is_string($input_name_for_attachments) ? $input_name_for_attachments : 'attachments'; + $input_name_for_removefiles = isset($input_name_for_removefiles) && is_string($input_name_for_removefiles) ? $input_name_for_removefiles : 'removefiles'; + $accept = isset($accept_only) && is_array($accept_only) && count($accept_only) > 0 ? ('accept="' . implode(",", $accept_only) . '"') : ''; + $acceptText = isset($accept_only) && is_array($accept_only) && count($accept_only) > 0 ? __('di tipo: "{0}"', implode(",", $accept_only)) : ''; + $georeferenced = isset($georeferenced) && $georeferenced; + $multiple = $georeferenced || isset($upload_single) && $upload_single ? '': 'multiple="multiple"'; + $oneFilePicker = isset($upload_single) && $upload_single; + $public_required = isset($public_required) && $public_required; + $required = isset($required) && $required; + $coRelated = isset($coRelated) && $coRelated; + + if (isset($enableRelated) && $enableRelated) { + echo ''; + echo ''; + } +?> +
+
+
+ ($oneFilePicker ? __('Allega un file ') : __('Allega files ')) . $acceptText]; + } + else + { + if($allow_private) + { + $attachment_scope = ['public' => __('Allega file pubblico ') . $acceptText, 'private' => ($oneFilePicker ? __('Allega un file privato ') : __('Allega files privati ')) . $acceptText]; + } + else + { + $attachment_scope = ['' => __('Allega files...')]; + } + } + + if(isset($tags)){ + $attachment_scope = []; + foreach ($tags as $tag => $description) { + $attachment_scope[$tag] = __('Allega files {1} {0}',$description,$acceptText); + } + $csv_tags = implode(',',array_keys($tags)); + } + if (isset($filepicker) && $filepicker) { + + $attachment_index = $georeferenced ? '[0]' : '[]'; + $col = (12 / count($attachment_scope)) > 6 ? (12 / count($attachment_scope)) : 6; + foreach($attachment_scope as $scope => $label) + { + echo '
'; + echo ''; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + } + + } + echo $this->Form->hidden($prefix.'removecurrentfiles', ['id' => $prefix.'removecurrentfiles', 'value' => isset($currentFilesRemovable) && $currentFilesRemovable ? 'true' : 'false']); +?> +
+ + +
+ +
+
+ + $label) + { + if ($scope == "public" || $oneFilePicker) { + continue; + } +?> + + + + + + + + + + + + +
+
+ +
+ +
+ + + +
diff --git a/idrocap_wa/templates/element/districtSelect.php b/idrocap_wa/templates/element/districtSelect.php new file mode 100644 index 0000000..a6b51f6 --- /dev/null +++ b/idrocap_wa/templates/element/districtSelect.php @@ -0,0 +1,210 @@ + $districtCellConfig->fieldId, + 'label' => __($districtCellConfig->fieldLabel), + 'type' => $districtCellConfig->fieldType->value, + "empty" => true, + "disabled" => $districtCellConfig->disabled, + 'required' => $districtCellConfig->fieldRequired +]; + +if (!empty($districtCellConfig->fieldValue)) { + $options['data-value'] = $districtCellConfig->fieldValue; +} +?> + +fieldId !== null && $districtCellConfig->fieldName !== null): ?> + Form->control($districtCellConfig->fieldName, $options) ?> + entity) && $districtCellConfig->entity->hasErrors($districtCellConfig->fieldName)): ?> +
+ entity->getError($districtCellConfig->fieldName); + + /* + * Qui ci finisco solo se siamo in un ciclo e quindi il nome del field non matcha con la rule + */ + if(empty($errors)) { + $errors = $districtCellConfig->entity->getError("district"); + } + + if (is_array($errors) && isset($errors['validDistrict'])) { + echo h($errors['validDistrict']); + } else { + echo is_array($errors) ? h(implode(', ', $errors)) : h($errors); + } + ?> +
+ + + + diff --git a/idrocap_wa/templates/element/flash/default.php b/idrocap_wa/templates/element/flash/default.php new file mode 100644 index 0000000..061c700 --- /dev/null +++ b/idrocap_wa/templates/element/flash/default.php @@ -0,0 +1,15 @@ + +
diff --git a/idrocap_wa/templates/element/flash/error.php b/idrocap_wa/templates/element/flash/error.php new file mode 100644 index 0000000..2ebf235 --- /dev/null +++ b/idrocap_wa/templates/element/flash/error.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/flash/info.php b/idrocap_wa/templates/element/flash/info.php new file mode 100644 index 0000000..e25b730 --- /dev/null +++ b/idrocap_wa/templates/element/flash/info.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/flash/success.php b/idrocap_wa/templates/element/flash/success.php new file mode 100644 index 0000000..73eaac4 --- /dev/null +++ b/idrocap_wa/templates/element/flash/success.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/flash/warning.php b/idrocap_wa/templates/element/flash/warning.php new file mode 100644 index 0000000..605537c --- /dev/null +++ b/idrocap_wa/templates/element/flash/warning.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/provinceSelect.php b/idrocap_wa/templates/element/provinceSelect.php new file mode 100644 index 0000000..ee9fb73 --- /dev/null +++ b/idrocap_wa/templates/element/provinceSelect.php @@ -0,0 +1,145 @@ + $provinceConfig->fieldId, + 'label' => __($provinceConfig->fieldLabel), + 'type' => $provinceConfig->fieldType->value, + "empty" => true, + 'options' => $provinces ?? [], + 'disabled' => $provinceConfig->disabled, + 'required' => $provinceConfig->fieldRequired +]; + +if (!empty($provinceConfig->fieldValue)) { + $options['value'] = $provinceConfig->fieldValue; +} + +$formContext = $provinceConfig->formContext ?? null; + +/** + * Passo il contesto perchè CakePHP genera una nuova VIEW e altrimenti non sarebbe visibile alla view dell'element. + * Vedi caso in cui dobbiamo gestire il valore selected per edit o view + * Inoltre anche nel caso di errori in questo caso manteniamo la gestione nativa di cakephp. + */ +if (isset($formContext)) { + $this->Form->create($formContext, ['type' => 'context', 'id' => false, 'url' => false]); +} +?> + +fieldId !== null && $provinceConfig->fieldName !== null): ?> + Form->control($provinceConfig->fieldName, $options) ?> + + + + Form->end(); + } +endif; ?> diff --git a/idrocap_wa/templates/email/html/default.php b/idrocap_wa/templates/email/html/default.php new file mode 100644 index 0000000..bf4c131 --- /dev/null +++ b/idrocap_wa/templates/email/html/default.php @@ -0,0 +1,22 @@ + ' . $line . "

\n"; +endforeach; diff --git a/idrocap_wa/templates/email/text/default.php b/idrocap_wa/templates/email/text/default.php new file mode 100644 index 0000000..bb8461e --- /dev/null +++ b/idrocap_wa/templates/email/text/default.php @@ -0,0 +1,18 @@ +fetch('content'); diff --git a/idrocap_wa/templates/layout/default.php b/idrocap_wa/templates/layout/default.php new file mode 100644 index 0000000..de042c7 --- /dev/null +++ b/idrocap_wa/templates/layout/default.php @@ -0,0 +1,47 @@ + + + + + Html->charset() ?> + + + <?= \Cake\Core\Configure::read('Theme.title') ?>: + <?= $this->fetch('title') ?> + + Html->meta('icon') ?> + + + + Html->css(['normalize.min', 'milligram.min', 'cake']) ?> + + fetch('meta') ?> + fetch('css') ?> + fetch('script') ?> + + +
+
+ Flash->render() ?> + fetch('content') ?> +
+
+
+
+ + diff --git a/idrocap_wa/templates/layout/email/html/default.php b/idrocap_wa/templates/layout/email/html/default.php new file mode 100644 index 0000000..96b0e73 --- /dev/null +++ b/idrocap_wa/templates/layout/email/html/default.php @@ -0,0 +1,25 @@ + + + + + <?= $this->fetch('title') ?> + + + fetch('content') ?> + + diff --git a/idrocap_wa/templates/layout/email/text/default.php b/idrocap_wa/templates/layout/email/text/default.php new file mode 100644 index 0000000..cd51169 --- /dev/null +++ b/idrocap_wa/templates/layout/email/text/default.php @@ -0,0 +1,17 @@ +fetch('content'); diff --git a/idrocap_wa/templates/layout/error.php b/idrocap_wa/templates/layout/error.php new file mode 100644 index 0000000..28c09ba --- /dev/null +++ b/idrocap_wa/templates/layout/error.php @@ -0,0 +1,41 @@ + + + + + Html->charset() ?> + + <?= $this->fetch('title') ?> + + Html->meta('icon') ?> + + + + Html->css(['normalize.min', 'milligram.min', 'cake']) ?> + + fetch('meta') ?> + fetch('css') ?> + fetch('script') ?> + + +
+ Flash->render() ?> + fetch('content') ?> + Html->link(__('Back'), 'javascript:history.back()') ?> +
+ + diff --git a/idrocap_wa/templates/layout/view_public.php b/idrocap_wa/templates/layout/view_public.php new file mode 100644 index 0000000..d44e591 --- /dev/null +++ b/idrocap_wa/templates/layout/view_public.php @@ -0,0 +1,68 @@ +CakeLte + */ + +?> + + + + + + + + <?= $this->fetch('title') . ' | ' . strip_tags($this->CakeLte->getConfig('app-name')) ?> + + Html->meta('icon') ?> + fetch('meta') ?> + + + + + Html->css('/adminlte/plugins/fontawesome-free/css/all.min.css') ?> + + Html->css('/adminlte/dist/css/adminlte.min.css') ?> + Html->css('CakeLte.style') ?> + Html->css('idrocap-styles') ?> + element('CakeLte.extra/css') ?> + + Html->css('citizen-registration.css') ?> + + fetch('css') ?> + + + + + + + + Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + + Html->script('/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js') ?> + + Html->script('/adminlte/dist/js/adminlte.min.js') ?> + + element('CakeLte.extra/script') ?> + fetch('script') ?> + + + \ No newline at end of file diff --git a/idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php b/idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php new file mode 100644 index 0000000..5bffbfb --- /dev/null +++ b/idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php @@ -0,0 +1,30 @@ +Html->icon($icon, $params['iconOptions']); + } + $message = $icon . "
$message
"; +} + +if (in_array('alert-dismissible', $class)) { + $button = << +BUTTON; + $message = $button . $message; +} +if (is_array($class)) { + $class = join(' ', $class); +} +echo $this->Html->div($class, $message, $params['attributes']); diff --git a/idrocap_wa/templates/plugin/CakeLte/element/footer/main.php b/idrocap_wa/templates/plugin/CakeLte/element/footer/main.php new file mode 100644 index 0000000..b132fe8 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/footer/main.php @@ -0,0 +1,14 @@ + + + +
+ Copyright © Privacy Policy. + +
+ + + + + diff --git a/idrocap_wa/templates/plugin/CakeLte/element/header/main.php b/idrocap_wa/templates/plugin/CakeLte/element/header/main.php new file mode 100644 index 0000000..4ac2fc1 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/header/main.php @@ -0,0 +1,21 @@ + + + + + diff --git a/idrocap_wa/templates/plugin/CakeLte/element/header/menu.php b/idrocap_wa/templates/plugin/CakeLte/element/header/menu.php new file mode 100644 index 0000000..a50ed2a --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/header/menu.php @@ -0,0 +1,2 @@ + +Sections->create($menu_sections) ?> diff --git a/idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php b/idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php new file mode 100644 index 0000000..b84917f --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php @@ -0,0 +1,51 @@ +Html->script('jixel-primitives'); ?> + +Notifications->create($user_notifications) ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php new file mode 100644 index 0000000..fd685e5 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php @@ -0,0 +1,6 @@ + + diff --git a/idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php new file mode 100644 index 0000000..203861d --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php @@ -0,0 +1,33 @@ + + + + + + + Menu->create($menu_items) ?> + + + Menu->create($sys_admin_menu_items); ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/plugin/CakeLte/layout/default.php b/idrocap_wa/templates/plugin/CakeLte/layout/default.php new file mode 100644 index 0000000..0d04294 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/layout/default.php @@ -0,0 +1,108 @@ +CakeLte + */ + +?> + + + + + + + + + <?= strip_tags($this->fetch('title') . ' | ' . $this->CakeLte->getConfig('app-name')) ?> + + Html->meta('icon') ?> + fetch('meta') ?> + + + + + Html->css('/adminlte/plugins/fontawesome-free/css/all.min.css') ?> + + Html->css('/adminlte/dist/css/adminlte.min.css') ?> + Html->css('CakeLte.style') ?> + Html->css('idrocap-styles') ?> + + Html->css('/bower_components/select2/dist/css/select2.min'); ?> + + Html->css('/adminlte/plugins/daterangepicker/daterangepicker') ?> + element('CakeLte.extra/css') ?> + fetch('css') ?> + + + +
+ + + + + + + + +
+ +
+
+ Flash->render() ?> + fetch('content') ?> +
+
+ +
+ + + + + + + +
+ element('CakeLte.footer/main') ?> +
+
+ + + + Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + + Html->script('/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js') ?> + + Html->script('/adminlte/dist/js/adminlte.min.js') ?> + + element('CakeLte.extra/script') ?> + + Html->script('/bower_components/select2/dist/js/select2.min'); ?> + + Html->script('/adminlte/plugins/daterangepicker/daterangepicker'); ?> + + fetch('script') ?> + + + diff --git a/idrocap_wa/templates/plugin/CakeLte/layout/login.php b/idrocap_wa/templates/plugin/CakeLte/layout/login.php new file mode 100644 index 0000000..965a9d9 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/layout/login.php @@ -0,0 +1,111 @@ +CakeLte + */ + +?> + + + + + + + + <?= $this->fetch('title') . ' | ' . strip_tags($this->CakeLte->getConfig('app-name')) ?> + + Html->meta('icon') ?> + fetch('meta') ?> + + + + + Html->css('/adminlte/plugins/fontawesome-free/css/all.min.css') ?> + + Html->css('/adminlte/dist/css/adminlte.min.css') ?> + Html->css('CakeLte.style') ?> + Html->css('idrocap-styles') ?> + element('CakeLte.extra/css') ?> + + Html->css('citizen-registration.css') ?> + + fetch('css') ?> + + + +
+ + + + + + + + +
+
+ + + + +
+ + + + + Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + + Html->script('/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js') ?> + + Html->script('/adminlte/dist/js/adminlte.min.js') ?> + + element('CakeLte.extra/script') ?> + fetch('script') ?> + + + + diff --git a/idrocap_wa/tests/Fixture/.gitkeep b/idrocap_wa/tests/Fixture/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/TestCase/ApplicationTest.php b/idrocap_wa/tests/TestCase/ApplicationTest.php new file mode 100644 index 0000000..6a65c52 --- /dev/null +++ b/idrocap_wa/tests/TestCase/ApplicationTest.php @@ -0,0 +1,85 @@ +bootstrap(); + $plugins = $app->getPlugins(); + + $this->assertTrue($plugins->has('Bake'), 'plugins has Bake?'); + $this->assertFalse($plugins->has('DebugKit'), 'plugins has DebugKit?'); + $this->assertTrue($plugins->has('Migrations'), 'plugins has Migrations?'); + } + + /** + * Test bootstrap add DebugKit plugin in debug mode. + * + * @return void + */ + public function testBootstrapInDebug() + { + Configure::write('debug', true); + $app = new Application(dirname(__DIR__, 2) . '/config'); + $app->bootstrap(); + $plugins = $app->getPlugins(); + + $this->assertTrue($plugins->has('DebugKit'), 'plugins has DebugKit?'); + } + + /** + * testMiddleware + * + * @return void + */ + public function testMiddleware() + { + $app = new Application(dirname(__DIR__, 2) . '/config'); + $middleware = new MiddlewareQueue(); + + $middleware = $app->middleware($middleware); + + $this->assertInstanceOf(ErrorHandlerMiddleware::class, $middleware->current()); + $middleware->seek(1); + $this->assertInstanceOf(AssetMiddleware::class, $middleware->current()); + $middleware->seek(2); + $this->assertInstanceOf(RoutingMiddleware::class, $middleware->current()); + } +} diff --git a/idrocap_wa/tests/TestCase/Controller/Component/.gitkeep b/idrocap_wa/tests/TestCase/Controller/Component/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php b/idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php new file mode 100644 index 0000000..73f9452 --- /dev/null +++ b/idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php @@ -0,0 +1,115 @@ +get('/pages/home'); + $this->assertResponseOk(); + $this->assertResponseContains('CakePHP'); + $this->assertResponseContains(''); + } + + /** + * Test that missing template renders 404 page in production + * + * @return void + */ + public function testMissingTemplate() + { + Configure::write('debug', false); + $this->get('/pages/not_existing'); + + $this->assertResponseError(); + $this->assertResponseContains('Error'); + } + + /** + * Test that missing template in debug mode renders missing_template error page + * + * @return void + */ + public function testMissingTemplateInDebug() + { + Configure::write('debug', true); + $this->get('/pages/not_existing'); + + $this->assertResponseFailure(); + $this->assertResponseContains('Missing Template'); + $this->assertResponseContains('stack-frames'); + $this->assertResponseContains('not_existing.php'); + } + + /** + * Test directory traversal protection + * + * @return void + */ + public function testDirectoryTraversalProtection() + { + $this->get('/pages/../Layout/ajax'); + $this->assertResponseCode(403); + $this->assertResponseContains('Forbidden'); + } + + /** + * Test that CSRF protection is applied to page rendering. + * + * @return void + */ + public function testCsrfAppliedError() + { + $this->post('/pages/home', ['hello' => 'world']); + + $this->assertResponseCode(403); + $this->assertResponseContains('CSRF'); + } + + /** + * Test that CSRF protection is applied to page rendering. + * + * @return void + */ + public function testCsrfAppliedOk() + { + $this->enableCsrfToken(); + $this->post('/pages/home', ['hello' => 'world']); + + $this->assertThat(403, $this->logicalNot(new StatusCode($this->_response))); + $this->assertResponseNotContains('CSRF'); + } +} diff --git a/idrocap_wa/tests/TestCase/Model/Behavior/.gitkeep b/idrocap_wa/tests/TestCase/Model/Behavior/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/TestCase/View/Helper/.gitkeep b/idrocap_wa/tests/TestCase/View/Helper/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/bootstrap.php b/idrocap_wa/tests/bootstrap.php new file mode 100644 index 0000000..1cb386d --- /dev/null +++ b/idrocap_wa/tests/bootstrap.php @@ -0,0 +1,66 @@ + 'Cake\Database\Connection', + 'driver' => 'Cake\Database\Driver\Sqlite', + 'database' => TMP . 'debug_kit.sqlite', + 'encoding' => 'utf8', + 'cacheMetadata' => true, + 'quoteIdentifiers' => false, +]); + +ConnectionManager::alias('test_debug_kit', 'debug_kit'); + +// Fixate sessionid early on, as php7.2+ +// does not allow the sessionid to be set after stdout +// has been written to. +session_id('cli'); + +// Use migrations to build test database schema. +// +// Will rebuild the database if the migration state differs +// from the migration history in files. +// +// If you are not using CakePHP's migrations you can +// hook into your migration tool of choice here or +// load schema from a SQL dump file with +// use Cake\TestSuite\Fixture\SchemaLoader; +// (new SchemaLoader())->loadSqlFiles('./tests/schema.sql', 'test'); + +(new Migrator())->run(); diff --git a/idrocap_wa/tests/schema.sql b/idrocap_wa/tests/schema.sql new file mode 100644 index 0000000..c7e4d3f --- /dev/null +++ b/idrocap_wa/tests/schema.sql @@ -0,0 +1,4 @@ +-- Test database schema. +-- +-- If you are not using CakePHP migrations you can put +-- your application's schema in this file and use it in tests. diff --git a/idrocap_wa/webroot/.gitignore b/idrocap_wa/webroot/.gitignore new file mode 100644 index 0000000..5cccb96 --- /dev/null +++ b/idrocap_wa/webroot/.gitignore @@ -0,0 +1,3 @@ +node_modules +bower_components + diff --git a/idrocap_wa/webroot/.htaccess b/idrocap_wa/webroot/.htaccess new file mode 100644 index 0000000..f5f2d63 --- /dev/null +++ b/idrocap_wa/webroot/.htaccess @@ -0,0 +1,5 @@ + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/idrocap_wa/webroot/adminlte b/idrocap_wa/webroot/adminlte new file mode 120000 index 0000000..be2cf15 --- /dev/null +++ b/idrocap_wa/webroot/adminlte @@ -0,0 +1 @@ +/var/www/jixel/vendor/almasaeed2010/adminlte/ \ No newline at end of file diff --git a/idrocap_wa/webroot/bower.json b/idrocap_wa/webroot/bower.json new file mode 100644 index 0000000..728e78e --- /dev/null +++ b/idrocap_wa/webroot/bower.json @@ -0,0 +1,17 @@ +{ + "name": "webroot", + "description": "", + "main": "", + "license": "MIT", + "homepage": "", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "select2": "~4.0" + } +} diff --git a/idrocap_wa/webroot/css/cake.css b/idrocap_wa/webroot/css/cake.css new file mode 100644 index 0000000..fbb0de9 --- /dev/null +++ b/idrocap_wa/webroot/css/cake.css @@ -0,0 +1,299 @@ +/* Milligram overrides */ +:root { + /* The following are official CakePHP colors */ + --color-cakephp-red: #d33c43; + --color-cakephp-gray: #404041; + --color-cakephp-blue: #2f85ae; + --color-cakephp-lightblue: #34bdd7; + + /* These are additional colors */ + --color-lightgray: #606c76; + --color-white: #fff; + + --color-main-bg: #f5f7fa; + --color-links: var(--color-cakephp-blue); + --color-links-active: #2a6496; + --color-headings: #363637; + + --color-message-success-bg: #e3fcec; + --color-message-success-text: #1f9d55; + --color-message-success-border: #51d88a; + + --color-message-warning-bg: #fffabc; + --color-message-warning-text: #8d7b00; + --color-message-warning-border: #d3b800; + + --color-message-error-bg: #fcebea; + --color-message-error-text: #cc1f1a; + --color-message-error-border: #ef5753; + + --color-message-info-bg: #eff8ff; + --color-message-info-text: #2779bd; + --color-message-info-border: #6cb2eb; +} + +.button, button, input[type='button'], input[type='reset'], input[type='submit'] { + background-color: var(--color-cakephp-red); + border-color: var(--color-cakephp-red); +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 400; + background: var(--color-main-bg); +} + +.top-nav-links, +.side-nav, +h1, h2, h3, h4, h5, h6 { + font-family: "Raleway", sans-serif; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 400; + color: var(--color-headings); +} + +a { + color: var(--color-links); + transition: color 0.2s linear; +} + +a:hover, +a:focus, +a:active { + color: var(--color-links-active); + transition: color 0.2s ease-out; +} + +.side-nav a, +.top-nav-links a, +th a, +.actions a { + color: var(--color-lightgray); +} + +.side-nav a:hover, +.side-nav a:focus, +.actions a:hover, +.actions a:focus { + color: var(--color-links-active); +} + +/* Utility */ +.table-responsive { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +/* Main */ +.content { + padding: 2rem; + background: var(--color-white); + border-radius: 0.4rem; + /* Thanks Stripe */ + box-shadow: 0 7px 14px 0 rgba(60, 66, 87, 0.1), + 0 3px 6px 0 rgba(0, 0, 0, 0.07); +} +.content form { + margin: 0; +} +.actions a { + font-weight: bold; + padding: 0 0.4rem; +} +.actions a:first-child { + padding-left: 0; +} +th { + white-space: nowrap; +} + +/* Nav bar */ +.top-nav { + display: flex; + align-items: center; + justify-content: space-between; + max-width: 112rem; + padding: 2rem; + margin: 0 auto; +} +.top-nav-title a { + font-size: 2.4rem; + color: var(--color-cakephp-red); +} +.top-nav-title span { + color: var(--color-cakephp-gray); +} +.top-nav-links a { + margin: 0 0.5rem; +} +.top-nav-title a, +.top-nav-links a { + font-weight: bold; +} +.side-nav-item { + display: block; + padding: 0.5rem 0; +} + +/* View action */ +.view.content .text { + margin-top: 1.2rem; +} +.related { + margin-top: 2rem; +} + +/* Flash messages */ +.message { + padding: .5rem 1rem; + background: var(--color-message-info-bg); + color: var(--color-message-info-text); + border-color: var(--color-message-info-border); + border-width: 1px; + border-style: solid; + border-radius: 4px; + margin-bottom: 1rem; + cursor: pointer; +} +.message.hidden { + display: none; +} +.message.success { + background: var(--color-message-success-bg); + color: var(--color-message-success-text); + border-color: var(--color-message-success-border); +} +.message.warning { + background: var(--color-message-warning-bg); + color: var(--color-message-warning-text); + border-color: var(--color-message-warning-border); +} +.message.error { + background: var(--color-message-error-bg); + color: var(--color-message-error-text); + border-color: var(--color-message-error-border); +} + +/* Forms */ +.input.radio, +.input.checkbox, +.input.multicheckbox { + margin-bottom: 2.0rem; +} +.input.radio input, +.input.checkbox input, +.input.multicheckbox input { + margin: 0; +} +.input.radio label, +.input.checkbox label, +.input.multicheckbox label { + margin: 0; + display: flex; + align-items: center; +} +.input.radio label > input, +.input.checkbox label > input, +.input.multicheckbox label > input { + margin-right: 1.0rem; +} +input[type='color'] { + max-width: 4rem; + padding: 0.3rem .5rem 0.3rem; +} + +/* Paginator */ +.paginator { + text-align: right; +} +.paginator p { + margin-bottom: 0; +} +.pagination { + display: flex; + justify-content: center; + list-style: none; + margin: 0 0 1rem 0; + padding: 0; +} +.pagination li { + display: inline-block; + margin: 0.25em; + text-align: center; +} +.pagination a { + color: var(--color-cakephp-blue); + display: inline-block; + font-size: 1.25rem; + line-height: 3rem; + min-width: 3rem; + padding: 0; + position: relative; + text-decoration: none; + transition: background .3s,color .3s; +} +.pagination li.active a, +.pagination a:hover { + text-decoration: underline; +} +.pagination .disabled a { + cursor: not-allowed; + color: var(--color-lightgray); + text-decoration: none; +} +.first a, +.prev a, +.next a, +.last a { + padding: 0 .75rem; +} +.disabled a:hover { + background: initial; + color: initial; +} +.asc:after { + content: " \2193"; +} +.desc:after { + content: " \2191"; +} + +/* Error in non debug mode */ +.error-container { + align-items: center; + display: flex; + flex-direction: column; + height: 100vh; + justify-content: center; +} + +@media screen and (max-width: 640px) { + /* Fix milligram not having a responsive column system */ + .row .column[class*='column-'] { + flex: 0 0 100%; + max-width: 100% + } + .top-nav { + margin: 0 auto; + } + .side-nav { + margin-bottom: 1rem; + } + .heading { + margin-bottom: 1rem; + } + .side-nav-item { + display: inline; + margin: 0 1.5rem 0 0; + } + .asc:after { + content: " \2192"; + } + .desc:after { + content: " \2190"; + } +} diff --git a/idrocap_wa/webroot/css/citizen-registration.css b/idrocap_wa/webroot/css/citizen-registration.css new file mode 100644 index 0000000..bf2f717 --- /dev/null +++ b/idrocap_wa/webroot/css/citizen-registration.css @@ -0,0 +1,14 @@ +.add-citizen.add-citizen { + width: 80%; +} + +.login-page { + margin-top: 76px; + margin-bottom: 76px; + padding-left: 20px; + padding-right: 20px; +} + +.card-primary.card-outline { + border-top: none; +} diff --git a/idrocap_wa/webroot/css/fonts.css b/idrocap_wa/webroot/css/fonts.css new file mode 100644 index 0000000..1ba4808 --- /dev/null +++ b/idrocap_wa/webroot/css/fonts.css @@ -0,0 +1,80 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/idrocap_wa/webroot/css/home.css b/idrocap_wa/webroot/css/home.css new file mode 100644 index 0000000..4648ed3 --- /dev/null +++ b/idrocap_wa/webroot/css/home.css @@ -0,0 +1,75 @@ +/* Home page styles */ +@font-face { + font-family: 'cakefont'; + src: url('../font/cakedingbats-webfont.eot'); + src: url('../font/cakedingbats-webfont.eot?#iefix') format('embedded-opentype'), + url('../font/cakedingbats-webfont.woff2') format('woff2'), + url('../font/cakedingbats-webfont.woff') format('woff'), + url('../font/cakedingbats-webfont.ttf') format('truetype'), + url('../font/cakedingbats-webfont.svg#cake_dingbatsregular') format('svg'); + font-weight: normal; + font-style: normal; +} +body { + padding: 60px 0; +} +header { + margin-bottom: 60px; +} +img { + margin-bottom: 30px; +} +h1 { + font-weight: bold; +} +ul { + list-style-type: none; + margin: 0 0 30px 0; + padding-left: 25px; +} +a { + color: #0071BC; + text-decoration: underline; +} +hr { + border-bottom: 1px solid #e7e7e7; + border-top: 0; + margin-bottom: 35px; +} + +.text-center { + text-align: center; +} +.links a { + margin-right: 10px; +} +.release-name { + color: #D33C43; + font-weight: 400; + font-style: italic; +} +.bullet:before { + font-family: 'cakefont', sans-serif; + font-size: 18px; + display: inline-block; + margin-left: -1.3em; + width: 1.2em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + vertical-align: -1px; +} +.success:before { + color: #88c671; + content: "\0056"; +} +.problem:before { + color: #d33d44; + content: "\0057"; +} +.cake-error { + padding: 10px; + margin: 10px 0; +} +#url-rewriting-warning { + display: none; +} diff --git a/idrocap_wa/webroot/css/idrocap-styles.css b/idrocap_wa/webroot/css/idrocap-styles.css new file mode 100644 index 0000000..a1bf189 --- /dev/null +++ b/idrocap_wa/webroot/css/idrocap-styles.css @@ -0,0 +1,33 @@ +.select2-container { + width: 100% !important; +} + +.select2-selection { + height: calc(2.25rem + 2px) !important; +} + +.select2-container--default .select2-selection--single .select2-selection__arrow.select2-selection__arrow { + top: 6px; +} + +.idrocap-filter-select { + width: 100%; + height: 2.25rem; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +.tox-promotion { + display: none; +} +.tox-statusbar__branding { + display: none; +} \ No newline at end of file diff --git a/idrocap_wa/webroot/css/jixel_ol.css b/idrocap_wa/webroot/css/jixel_ol.css new file mode 100644 index 0000000..7449f92 --- /dev/null +++ b/idrocap_wa/webroot/css/jixel_ol.css @@ -0,0 +1,66 @@ +.jixel-ol-tools-button { + top: 65px; + left: .5em; +} + +.ol-attribution li { + font-size: 1.3rem; +} + +.layerup { + display:none !important; +} + +.ol-layerswitcher .panel li label { + max-width: 40em !important; +} +.olmap { + height: 500px; + width: 100%; +} +.jixel-ol-popup { + position: absolute; + background-color: white; + -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + padding: 15px; + border-radius: 10px; + border: 1px solid #cccccc; + bottom: 12px; + left: -50px; + min-width: 280px; +} +.jixel-ol-popup:after, .jixel-ol-popup:before { + top: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} +.jixel-ol-popup:after { + border-top-color: white; + border-width: 10px; + left: 48px; + margin-left: -10px; +} +.jixel-ol-popup:before { + border-top-color: #cccccc; + border-width: 11px; + left: 48px; + margin-left: -11px; +} +.jixel-ol-popup-closer { + text-decoration: none; + position: absolute; + top: 5px; + right: 10px; +} +.jixel-ol-popup-closer:after { + content: "✖"; +} +.jixel-ol-popup-content { + height: 200px; + overflow-y: scroll; +} diff --git a/idrocap_wa/webroot/css/milligram.min.css b/idrocap_wa/webroot/css/milligram.min.css new file mode 100644 index 0000000..958f687 --- /dev/null +++ b/idrocap_wa/webroot/css/milligram.min.css @@ -0,0 +1,9 @@ +/*! + * Milligram v1.4.1 + * https://milligram.io + * + * Copyright (c) 2020 CJ Patoilo + * Licensed under the MIT license + */ + +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;font-family:'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#9b4dca;border:0.1rem solid #9b4dca;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#9b4dca;border-color:#9b4dca}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#9b4dca}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#9b4dca}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#9b4dca}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#9b4dca}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #9b4dca;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#9b4dca;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#9b4dca;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} diff --git a/idrocap_wa/webroot/css/normalize.min.css b/idrocap_wa/webroot/css/normalize.min.css new file mode 100644 index 0000000..bde07fc --- /dev/null +++ b/idrocap_wa/webroot/css/normalize.min.css @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using clean-css v4.2.1. + * Original file: /npm/normalize.css@8.0.1/normalize.css + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} diff --git a/idrocap_wa/webroot/favicon.ico b/idrocap_wa/webroot/favicon.ico new file mode 100644 index 0000000..86c1a8c Binary files /dev/null and b/idrocap_wa/webroot/favicon.ico differ diff --git a/idrocap_wa/webroot/favicon2.ico b/idrocap_wa/webroot/favicon2.ico new file mode 100644 index 0000000..49a060f Binary files /dev/null and b/idrocap_wa/webroot/favicon2.ico differ diff --git a/idrocap_wa/webroot/font/Raleway-License.txt b/idrocap_wa/webroot/font/Raleway-License.txt new file mode 100644 index 0000000..94dce24 --- /dev/null +++ b/idrocap_wa/webroot/font/Raleway-License.txt @@ -0,0 +1,51 @@ +License for 'Raleway' +SIL Open Font License +Copyright (c) 2010, Matt McInerney (matt@pixelspread.com), +Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com), +Copyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +—————————————————————————————- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +—————————————————————————————- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +“Reserved Font Name” refers to any names specified as such after the copyright statement(s). + +“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.eot b/idrocap_wa/webroot/font/cakedingbats-webfont.eot new file mode 100644 index 0000000..e8605d9 Binary files /dev/null and b/idrocap_wa/webroot/font/cakedingbats-webfont.eot differ diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.svg b/idrocap_wa/webroot/font/cakedingbats-webfont.svg new file mode 100644 index 0000000..d1e0c98 --- /dev/null +++ b/idrocap_wa/webroot/font/cakedingbats-webfont.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.ttf b/idrocap_wa/webroot/font/cakedingbats-webfont.ttf new file mode 100644 index 0000000..13d5445 Binary files /dev/null and b/idrocap_wa/webroot/font/cakedingbats-webfont.ttf differ diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.woff b/idrocap_wa/webroot/font/cakedingbats-webfont.woff new file mode 100644 index 0000000..073baab Binary files /dev/null and b/idrocap_wa/webroot/font/cakedingbats-webfont.woff differ diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.woff2 b/idrocap_wa/webroot/font/cakedingbats-webfont.woff2 new file mode 100644 index 0000000..6e71eaf Binary files /dev/null and b/idrocap_wa/webroot/font/cakedingbats-webfont.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-400-cyrillic-ext.woff2 b/idrocap_wa/webroot/font/raleway-400-cyrillic-ext.woff2 new file mode 100644 index 0000000..039269e Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-400-cyrillic-ext.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-400-cyrillic.woff2 b/idrocap_wa/webroot/font/raleway-400-cyrillic.woff2 new file mode 100644 index 0000000..48b9d89 Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-400-cyrillic.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-400-latin-ext.woff2 b/idrocap_wa/webroot/font/raleway-400-latin-ext.woff2 new file mode 100644 index 0000000..0eedc5b Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-400-latin-ext.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-400-latin.woff2 b/idrocap_wa/webroot/font/raleway-400-latin.woff2 new file mode 100644 index 0000000..d0e6f01 Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-400-latin.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-400-vietnamese.woff2 b/idrocap_wa/webroot/font/raleway-400-vietnamese.woff2 new file mode 100644 index 0000000..405fb25 Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-400-vietnamese.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-700-cyrillic-ext.woff2 b/idrocap_wa/webroot/font/raleway-700-cyrillic-ext.woff2 new file mode 100644 index 0000000..039269e Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-700-cyrillic-ext.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-700-cyrillic.woff2 b/idrocap_wa/webroot/font/raleway-700-cyrillic.woff2 new file mode 100644 index 0000000..48b9d89 Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-700-cyrillic.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-700-latin-ext.woff2 b/idrocap_wa/webroot/font/raleway-700-latin-ext.woff2 new file mode 100644 index 0000000..0eedc5b Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-700-latin-ext.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-700-latin.woff2 b/idrocap_wa/webroot/font/raleway-700-latin.woff2 new file mode 100644 index 0000000..d0e6f01 Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-700-latin.woff2 differ diff --git a/idrocap_wa/webroot/font/raleway-700-vietnamese.woff2 b/idrocap_wa/webroot/font/raleway-700-vietnamese.woff2 new file mode 100644 index 0000000..405fb25 Binary files /dev/null and b/idrocap_wa/webroot/font/raleway-700-vietnamese.woff2 differ diff --git a/idrocap_wa/webroot/img/cake-logo.png b/idrocap_wa/webroot/img/cake-logo.png new file mode 100644 index 0000000..41939ef Binary files /dev/null and b/idrocap_wa/webroot/img/cake-logo.png differ diff --git a/idrocap_wa/webroot/img/cake.icon.png b/idrocap_wa/webroot/img/cake.icon.png new file mode 100644 index 0000000..394fa42 Binary files /dev/null and b/idrocap_wa/webroot/img/cake.icon.png differ diff --git a/idrocap_wa/webroot/img/cake.icon.svg b/idrocap_wa/webroot/img/cake.icon.svg new file mode 100644 index 0000000..38d2864 --- /dev/null +++ b/idrocap_wa/webroot/img/cake.icon.svg @@ -0,0 +1,7 @@ + + + Combined Shape + + + + \ No newline at end of file diff --git a/idrocap_wa/webroot/img/cake.logo.svg b/idrocap_wa/webroot/img/cake.logo.svg new file mode 100644 index 0000000..e73abb5 --- /dev/null +++ b/idrocap_wa/webroot/img/cake.logo.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/idrocap_wa/webroot/img/cake.power.gif b/idrocap_wa/webroot/img/cake.power.gif new file mode 100644 index 0000000..8f8d570 Binary files /dev/null and b/idrocap_wa/webroot/img/cake.power.gif differ diff --git a/idrocap_wa/webroot/img/logo-autorita-dibacino.png b/idrocap_wa/webroot/img/logo-autorita-dibacino.png new file mode 100644 index 0000000..7767261 Binary files /dev/null and b/idrocap_wa/webroot/img/logo-autorita-dibacino.png differ diff --git a/idrocap_wa/webroot/img/logo-fsc.png b/idrocap_wa/webroot/img/logo-fsc.png new file mode 100644 index 0000000..4c2cb61 Binary files /dev/null and b/idrocap_wa/webroot/img/logo-fsc.png differ diff --git a/idrocap_wa/webroot/img/logo-poa.png b/idrocap_wa/webroot/img/logo-poa.png new file mode 100644 index 0000000..362268c Binary files /dev/null and b/idrocap_wa/webroot/img/logo-poa.png differ diff --git a/idrocap_wa/webroot/img/logo-regione-sicilia.png b/idrocap_wa/webroot/img/logo-regione-sicilia.png new file mode 100644 index 0000000..4209dd4 Binary files /dev/null and b/idrocap_wa/webroot/img/logo-regione-sicilia.png differ diff --git a/idrocap_wa/webroot/img/logo_mite.png b/idrocap_wa/webroot/img/logo_mite.png new file mode 100644 index 0000000..f5d3f1d Binary files /dev/null and b/idrocap_wa/webroot/img/logo_mite.png differ diff --git a/idrocap_wa/webroot/img/user2-160x160.jpg b/idrocap_wa/webroot/img/user2-160x160.jpg new file mode 100644 index 0000000..aec74cb Binary files /dev/null and b/idrocap_wa/webroot/img/user2-160x160.jpg differ diff --git a/idrocap_wa/webroot/index.php b/idrocap_wa/webroot/index.php new file mode 100644 index 0000000..544b479 --- /dev/null +++ b/idrocap_wa/webroot/index.php @@ -0,0 +1,37 @@ +emit($server->run()); diff --git a/idrocap_wa/webroot/js/.gitkeep b/idrocap_wa/webroot/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/content.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/content.js new file mode 100644 index 0000000..d1a790a --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/content.js @@ -0,0 +1,27 @@ +import { TaskFlow } from "./utils/TaskFlow.js"; +document.addEventListener('DOMContentLoaded', () => { + try { + const container = document.createElement('div'); + document.body.appendChild(container); + const shadowRoot = container.attachShadow({ mode: 'open' }); + const uiContainer = document.createElement('div'); + const style = document.createElement('style'); + shadowRoot.appendChild(style); + const cssPath = `${window.location.origin}/js/ia-form-filler/styles/style.css`; + // Fetch e inietta il CSS dal file esterno + fetch(cssPath) + .then(response => response.text()) + .then(css => { + style.textContent = css; + uiContainer.style.cssText = 'position: absolute; top: 0; left: 0; z-index: 9999;'; + shadowRoot.appendChild(uiContainer); + TaskFlow.run(uiContainer); + }) + .catch(error => { + console.error("Errore durante il caricamento del CSS:", error); + }); + } + catch (error) { + console.error("Errore durante il caricamento di TaskFlow:", error); + } +}); diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Autocomplete/AutocompleteHandler.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Autocomplete/AutocompleteHandler.js new file mode 100644 index 0000000..3d9393c --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Autocomplete/AutocompleteHandler.js @@ -0,0 +1,69 @@ +import { EventHandler } from "../Utility/EventHandler.js"; +import { DomElementHandler } from "../Utility/DomElementHandler.js"; +import { TaskFlow } from "../TaskFlow.js"; +export class AutocompleteHandler { + static configureShadowContainer(container) { + AutocompleteHandler.container = container; + } + static addTaskFlowWidget() { + if (AutocompleteHandler.mainBoxContainer) { + return; + } + AutocompleteHandler.mainBoxContainer = AutocompleteHandler.createMainBoxContainer(); + AutocompleteHandler.container.appendChild(AutocompleteHandler.mainBoxContainer); + } + static createMainBoxContainer() { + const mainBoxContainer = DomElementHandler.createElement('div', AutocompleteHandler.mainContainerClass); + const icon = DomElementHandler.createElement('span', `autocomplete-icon`, { innerText: AutocompleteHandler.iaPluginData ? '🪄' : '❌' }); + const tooltip = DomElementHandler.createElement('span', 'autocomplete-icon-tooltip', { innerText: "Per utilizzare l'intelligenza artificiale è necessario effettuare l'upload di almeno uno dei seguenti documenti: Decreto (DEC), Disciplinare (DSC) o Licenza di attingimento (LIC)." }); + mainBoxContainer.append(icon); + if (!AutocompleteHandler.iaPluginData) { + mainBoxContainer.append(tooltip); + } + AutocompleteHandler.isRunning = false; + EventHandler.attachEvent('click', icon, (event) => { + event.stopPropagation(); + if (AutocompleteHandler.isRunning) { + console.log("is disabled"); + return; + } + if (!AutocompleteHandler.iaPluginData) { + return; + } + if (icon.innerText === '❌') { + icon.innerText = '🪄'; + mainBoxContainer.removeChild(tooltip); + } + AutocompleteHandler.executeFormAutoComplete(); + AutocompleteHandler.isRunning = true; + AutocompleteHandler.startFillingAnimation(); + document.addEventListener('StopAutofillAnimationCompletion', (event) => { + event.preventDefault(); + console.log('fetch completed', event); + AutocompleteHandler.stopFillingAnimation(); + tooltip.innerText = 'Errore durante il completamento automatico, si prega di riprovare.'; + mainBoxContainer.append(tooltip); + }); + document.addEventListener('autocompleteServiceError', (event) => { + setTimeout(() => { + icon.innerText = '❌'; + }, 1000); + }); + }); + return mainBoxContainer; + } + static startFillingAnimation() { + this.mainBoxContainer.style.animation = 'spinCoin 1s linear infinite'; + this.mainBoxContainer.style.cursor = 'not-allowed'; + } + static stopFillingAnimation() { + AutocompleteHandler.mainBoxContainer.style.animation = ''; + AutocompleteHandler.mainBoxContainer.style.cursor = ''; + AutocompleteHandler.isRunning = false; + } + static executeFormAutoComplete() { + TaskFlow.runFullFormAutoComplete(); + } +} +AutocompleteHandler.iaPluginData = window === null || window === void 0 ? void 0 : window.iaPluginData; +AutocompleteHandler.mainContainerClass = `task-flow-manager-extensions-popup-container ${!AutocompleteHandler.iaPluginData ? 'autocomplete-disabled' : ''}`; diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/BaseClient.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/BaseClient.js new file mode 100644 index 0000000..304b8f8 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/BaseClient.js @@ -0,0 +1,38 @@ +export class BaseClient { + constructor(baseUrl) { + this.baseUrl = baseUrl; + } + async get(endpoint, headers = {}) { + const response = await fetch(`${this.baseUrl}${endpoint}`, { + method: 'GET', + headers + }); + return this.handleResponse(response); + } + async post(endpoint, body, headers = {}) { + var _a; + const csrfToken = document.querySelector('[name="_csrfToken"]'); + headers['X-CSRF-Token'] = (_a = csrfToken === null || csrfToken === void 0 ? void 0 : csrfToken.value) !== null && _a !== void 0 ? _a : ''; + const response = await fetch(`${this.baseUrl}${endpoint}`, { + method: 'POST', + headers: Object.assign({ 'Content-Type': 'application/json' }, headers), + body: JSON.stringify(body) + }); + return this.handleResponse(response); + } + async handleResponse(response) { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + return response.json(); + } + parseResponse(response) { + const parsedResponse = Object.keys(response).reduce((acc, key) => { + // @ts-ignore + const newKey = key.replaceAll('_', '-'); + acc[newKey] = response[key]; + return acc; + }, {}); + return JSON.stringify(parsedResponse); + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/OpenAIClient.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/OpenAIClient.js new file mode 100644 index 0000000..a1e4cc3 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/OpenAIClient.js @@ -0,0 +1,39 @@ +import { BaseClient } from "./BaseClient.js"; +export class OpenAIClient extends BaseClient { + constructor(apiKey) { + super("https://api.openai.com/v1"); + this.apiKey = apiKey; + } + async fetchAutoComplete(prompt, model = "gpt-4o-mini", temperature = 0.7) { + const headers = { + 'Authorization': `Bearer ${this.apiKey}` + }; + let messages = []; + if (prompt === null || prompt === void 0 ? void 0 : prompt.systemPrompt) { + messages.push({ role: "system", content: prompt.systemPrompt }); + } + if (prompt === null || prompt === void 0 ? void 0 : prompt.userPrompt) { + messages.push({ role: "user", content: prompt.userPrompt + " " + prompt.systemPrompt }); + } + const body = { + model, + messages, + temperature + }; + return this.post('/chat/completions', body, headers); + // return fake post + /* return new Promise((resolve) => { + setTimeout(() => { + resolve({ + choices: [ + { + message: { + content: `{"${prompt.systemPrompt}": "fake value"}` + } + } + ] + }); + }, 1000); + });*/ + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/WgsAIClient.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/WgsAIClient.js new file mode 100644 index 0000000..99c8aef --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/WgsAIClient.js @@ -0,0 +1,10 @@ +import { BaseClient } from "./BaseClient.js"; +export class WgsAIClient extends BaseClient { + constructor() { + super("/"); + } + async fetchAutoComplete(prompt) { + const body = Object.assign({}, prompt); + return this.post('ai_services/autocomplete', body); + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Interfaces/PromptInterface.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Interfaces/PromptInterface.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Interfaces/PromptInterface.js @@ -0,0 +1 @@ +export {}; diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Services/AutoCompleteService.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Services/AutoCompleteService.js new file mode 100644 index 0000000..a91d8f0 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Services/AutoCompleteService.js @@ -0,0 +1,34 @@ +import { WgsAIClient } from "../Clients/WgsAIClient.js"; +import { DataFormatter } from "../Utility/DataFormatter.js"; +import { AutocompleteHandler } from "../Autocomplete/AutocompleteHandler.js"; +export class AutoCompleteService { + static async fetchFullFormAutoComplete(fields, contextText = '') { + try { + const response = await AutoCompleteService.client.fetchAutoComplete(AutocompleteHandler.iaPluginData); + const parsedResponse = AutoCompleteService.client.parseResponse(response.result); + return DataFormatter.parseAutoCompleteJson(parsedResponse, fields.map(field => field.name)); + } + catch (error) { + console.error("Errore nel completamento:", error); + const errorStatus = new CustomEvent('autocompleteServiceError', { + detail: { + message: error + } + }); + document.dispatchEvent(errorStatus); + return fields.reduce((acc, field) => (Object.assign(Object.assign({}, acc), { [field.name]: "" })), {}); + } + finally { + setTimeout(() => { + const stopAnimationEvent = new CustomEvent("StopAutofillAnimationCompletion", { + detail: { + message: "Autocompletion call completed", + timestamp: new Date() + } + }); + document.dispatchEvent(stopAnimationEvent); + }, 4000); + } + } +} +AutoCompleteService.client = new WgsAIClient(); diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/TaskFlow.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/TaskFlow.js new file mode 100644 index 0000000..9b3bb70 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/TaskFlow.js @@ -0,0 +1,15 @@ +import { FormAnalyzer } from "./Utility/FormAnalyzer.js"; +import { AutoCompleteService } from "./Services/AutoCompleteService.js"; +import { FormFiller } from "./Utility/FormFiller.js"; +import { AutocompleteHandler } from "./Autocomplete/AutocompleteHandler.js"; +export class TaskFlow { + static async run(container) { + AutocompleteHandler.configureShadowContainer(container); + AutocompleteHandler.addTaskFlowWidget(); + } + static async runFullFormAutoComplete() { + const inputs = FormAnalyzer.getInputs(); + const result = await AutoCompleteService.fetchFullFormAutoComplete(inputs); + await FormFiller.typeIntoForm(inputs, result); + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DataFormatter.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DataFormatter.js new file mode 100644 index 0000000..5738838 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DataFormatter.js @@ -0,0 +1,55 @@ +export class DataFormatter { + static parseAutoCompleteJson(content, fieldNames) { + let jsonString = content; + const jsonMatch = content.match(/```json\s*([\s\S]*?)\s*```/i) + || content.match(/```[\s\S]*?```/i) + || content.match(/{[\s\S]*}/); + if (jsonMatch && jsonMatch[1]) { + jsonString = jsonMatch[1]; + } + else if (jsonMatch) { + jsonString = jsonMatch[0]; + } + jsonString = jsonString.trim(); + try { + const parsedJson = JSON.parse(jsonString); + const result = {}; + fieldNames.forEach(fieldName => { + if (parsedJson.hasOwnProperty(fieldName)) { + result[fieldName] = String(parsedJson[fieldName]); + } /* else { + result[fieldName] = ""; + }*/ + }); + return result; + } + catch (error) { + console.error("Errore nel parsing del JSON iniziale:", error); + jsonString = DataFormatter.fixCommonJsonErrors(jsonString); + try { + const parsedJson = JSON.parse(jsonString); + const result = {}; + fieldNames.forEach(fieldName => { + if (parsedJson.hasOwnProperty(fieldName)) { + result[fieldName] = String(parsedJson[fieldName]); + } + else { + result[fieldName] = ""; + } + }); + return result; + } + catch (e) { + console.error("Errore nel parsing del JSON dopo le correzioni:", e); + return fieldNames.reduce((acc, fieldName) => (Object.assign(Object.assign({}, acc), { [fieldName]: "" })), {}); + } + } + } + static fixCommonJsonErrors(jsonString) { + jsonString = jsonString.replace(/'/g, '"'); + jsonString = jsonString.replace(/,\s*([}\]])/g, '$1'); + jsonString = jsonString.replace(/^[^\{]*\{/, '{').replace(/\}[^\}]*$/, '}'); + jsonString = jsonString.replace(/[\u0000-\u0019]+/g, ''); + return jsonString; + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DomElementHandler.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DomElementHandler.js new file mode 100644 index 0000000..7e12132 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DomElementHandler.js @@ -0,0 +1,26 @@ +export class DomElementHandler { +} +DomElementHandler.createElement = (element, className, attributes, parent) => { + const newElement = document.createElement(element); + newElement.className = className; + if (attributes) { + DomElementHandler.setProperties(newElement, attributes); + } + if (parent) { + parent.appendChild(newElement); + } + return newElement; +}; +DomElementHandler.setProperty = (element, property, value) => { + if (element && property in element) { + element[property] = value; + } + else { + console.warn(`Property ${property} does not exist on the element.`); + } +}; +DomElementHandler.setProperties = (element, properties) => { + for (const property in properties) { + DomElementHandler.setProperty(element, property, properties[property]); + } +}; diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/EventHandler.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/EventHandler.js new file mode 100644 index 0000000..83a1824 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/EventHandler.js @@ -0,0 +1,5 @@ +export class EventHandler { + static attachEvent(type, element, funcToCall) { + element.addEventListener(type, (event) => funcToCall(event)); + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormAnalyzer.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormAnalyzer.js new file mode 100644 index 0000000..89b6440 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormAnalyzer.js @@ -0,0 +1,137 @@ +import { FormExclusions } from "./FormExclusions.js"; +export class FormAnalyzer { + static getInputs(getAll = false) { + const forms = document.querySelectorAll('form'); + const inputs = []; + let form = {}; + if (forms.length > 0) { + let max = 0; + forms.forEach(f => { + const inputs = f.querySelectorAll('input'); + const selects = f.querySelectorAll('select'); + const textareas = f.querySelectorAll('textarea'); + const total = inputs.length + selects.length + textareas.length; + if (total > max) { + max = total; + form = f; + } + }); + } + if (Object.keys(form).length === 0 || form === undefined || form === null) { + return inputs; + } + const formInputs = form.querySelectorAll('input'); + formInputs.forEach(input => { + if (input.type !== 'button' && input.type !== 'submit' && input.type !== 'radio') { + const nameOrId = input.id || input.name; + if (FormExclusions.isExcluded(nameOrId)) { + console.log('is excluded', nameOrId); + return; + } + if (FormExclusions.isDisabled(input)) { + return; + } + if (FormExclusions.isReadonly(input)) { + return; + } + if (FormExclusions.isHidden(input)) { + return; + } + let inputType; + switch (input.getAttribute('type')) { + case 'text': { + inputType = 'text'; + break; + } + case 'checkbox': { + inputType = 'checkbox'; + break; + } + case 'date': { + console.log('is date'); + inputType = 'date'; + break; + } + case 'file': { + inputType = 'file'; + break; + } + default: { + inputType = 'input'; + } + } + if (nameOrId) { + inputs.push({ + name: nameOrId, + element: input, + type: inputType, + value: input.value + }); + } + } + }); + const formSelects = form.querySelectorAll('select'); + formSelects.forEach(select => { + const nameOrId = select.id || select.name; + if (FormExclusions.isExcluded(nameOrId)) { + console.log('is excluded', nameOrId); + return; + } + if (FormExclusions.isDisabled(select)) { + return; + } + if (FormExclusions.isReadonly(select)) { + return; + } + if (FormExclusions.isHidden(select)) { + return; + } + if (nameOrId) { + if (select.className.includes('select2')) { + return; + } + const options = Array.from(select.options).map(option => { + let value = option.value.trim(); + let text = option.text.trim(); + return { + value, + text + }; + }); + inputs.push({ + name: nameOrId, + element: select, + type: 'select', + options: options, + value: '' + }); + } + }); + const formTextAreas = form.querySelectorAll('textarea'); + formTextAreas.forEach(textarea => { + const nameOrId = textarea.id || textarea.name; + if (FormExclusions.isExcluded(nameOrId)) { + console.log('is excluded', nameOrId); + return; + } + if (FormExclusions.isDisabled(textarea)) { + return; + } + if (FormExclusions.isReadonly(textarea)) { + return; + } + if (FormExclusions.isHidden(textarea)) { + return; + } + if (nameOrId) { + inputs.push({ + name: nameOrId, + element: textarea, + type: 'textarea', + value: textarea === null || textarea === void 0 ? void 0 : textarea.value + }); + } + }); + return inputs; + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormExclusions.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormExclusions.js new file mode 100644 index 0000000..ca2c5b3 --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormExclusions.js @@ -0,0 +1,25 @@ +export class FormExclusions { + static isExcluded(nameOrId) { + return FormExclusions.excludedNames.includes(nameOrId) || FormExclusions.excludedIds.includes(nameOrId); + } + static isDisabled(element) { + return element.hasAttribute('disabled'); + } + static isHidden(element) { + if (element instanceof HTMLInputElement) { + return element.type === 'hidden'; + } + else if (element instanceof HTMLTextAreaElement) { + return element.type === 'hidden'; + } + else if (element instanceof HTMLElement) { + return element.style.display === 'none'; + } + return false; + } + static isReadonly(element) { + return element.hasAttribute('readonly'); + } +} +FormExclusions.excludedIds = []; +FormExclusions.excludedNames = []; diff --git a/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormFiller.js b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormFiller.js new file mode 100644 index 0000000..d6a28be --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormFiller.js @@ -0,0 +1,112 @@ +export class FormFiller { + static async fillField(input, value) { + if (input.type === 'input' || input.type === 'text') { + const element = input.element; + if (element.type === 'file') { + console.warn(`Cannot set value for input type="file": ${input.name}`); + return; + } + await this.typeIntoInput(element, value); + } + else if (input.type === 'select') { + let options = []; + if (input.options && typeof input.options[0] !== 'string') { + options = input.options.map(option => option.value); + } + else if (input.options) { + options = input.options; + } + if (options.includes(value)) { + await this.selectOption(input.element, value); + } + else if (options.length > 0) { + await this.selectOption(input.element, options[0]); + } + } + else if (input.type === 'textarea') { + await this.typeIntoInput(input.element, value); + } + else if (input.type === 'checkbox') { + const element = input.element; + if (value === "true" || value === '1') { + element.checked = true; + element.dispatchEvent(new Event('change')); + } + else { + element.checked = false; + element.dispatchEvent(new Event('change')); + } + } + else if (input.type === 'date') { + const element = input.element; + try { + element.focus(); + element.scrollIntoView({ behavior: "smooth", block: "center" }); + setTimeout(() => { + element.value = value; + element.dispatchEvent(new Event('input')); + element.dispatchEvent(new Event('change')); + element.blur(); + }, 400); + } + catch (error) { + console.error(`Errore durante l'assegnazione del valore per il campo 'date': ${input.name}`); + } + } + } + static async typeIntoInput(element, text) { + if (element instanceof HTMLInputElement && element.type === 'file') { + console.warn(`Cannot set value for input type="${element.type}": ${element.name}`); + return; + } + element.scrollIntoView({ behavior: "smooth", block: "center" }); + element.focus(); + element.value = ""; + for (const char of text) { + element.dispatchEvent(new KeyboardEvent('keydown', { key: char })); + element.dispatchEvent(new KeyboardEvent('keypress', { key: char })); + element.value += char; + element.dispatchEvent(new Event('input')); + const length = element.value.length; + element.setSelectionRange(length, length); + if (element instanceof HTMLInputElement) { + if (element.scrollWidth > element.clientWidth) { + element.scrollLeft = element.scrollWidth; + element.dispatchEvent(new Event('scroll', { bubbles: false, cancelable: false })); + } + } + else if (element instanceof HTMLTextAreaElement) { + if (element.scrollHeight > element.clientHeight) { + element.scrollTop = element.scrollHeight; + element.dispatchEvent(new Event('scroll', { bubbles: false, cancelable: false })); + element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); + } + } + element.dispatchEvent(new KeyboardEvent('keyup', { key: char })); + // Ritardo per simulare l'effetto di typing + await new Promise(resolve => setTimeout(resolve, 100)); + } + } + static async selectOption(element, value) { + element.focus(); + const options = Array.from(element.options); + const optionToSelect = options.find(option => option.value === value || option.text === value); + if (optionToSelect) { + element.value = optionToSelect.value; + element.dispatchEvent(new Event('change')); + } + } + static async typeIntoForm(inputs, formData) { + for (const input of inputs) { + // skippiamo gli input che hanno già un valore + if (input.value.trim() !== '') { + console.log('skippo', input.name, input.value); + continue; + } + if (formData[input.name]) { + console.log("current value", input.value, input.name); + await this.fillField(input, formData[input.name]); + } + } + } +} diff --git a/idrocap_wa/webroot/js/ia-form-filler/styles/style.css b/idrocap_wa/webroot/js/ia-form-filler/styles/style.css new file mode 100644 index 0000000..2c8c27d --- /dev/null +++ b/idrocap_wa/webroot/js/ia-form-filler/styles/style.css @@ -0,0 +1,228 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +.task-flow-manager-extensions-popup-container { + position: fixed; + bottom: 20px; + right: 20px; + width: 60px; + height: 60px; + background: white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 9999; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); + border: 1px solid #ccc; + flex-direction: column; + transition: all 0.1s ease; + max-width: 60px; + max-height: 60px; +} + +.task-flow-manager-extensions-popup-container:not(.autocomplete-disabled):hover { + background: whitesmoke; + color: #4B0082; + transform: scale(1.2); + box-shadow: 0 0 10px rgba(255, 215, 0, 0.1); +} + +.task-flow-manager-extensions-popup-container.expanded { + width: 100%; + height: 100%; + max-width: 375px; + max-height: 350px; + border-radius: 15px; + +} + +.task-flow-manager-extensions-popup-container.autocomplete-disabled { + cursor: not-allowed;; +} + +.task-flow-manager-extensions-popup-container .autocomplete-icon { + font-size: 24px; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + user-select: none; +} + +.task-flow-manager-extensions-popup-container.expanded .autocomplete-icon { + display: none; +} + +.task-flow-manager-extensions-popup-container .autocomplete-options { + width: 100%; + background: transparent; + font-size: 16px; + display: flex; + margin-top: auto; +} + +.task-flow-manager-extensions-popup-container .autocomplete-form-option { + padding: 10px; + cursor: pointer; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + background: #FFD700; + color: #070063; + box-shadow: 0 2px 4px rgba(255, 215, 0, 0.1); + text-align: center; + text-transform: uppercase; + margin-top: auto; + font-weight: bold; + transition: all 0.3s ease; + width: 100%; + border: none; +} + +.task-flow-manager-extensions-popup-container .autocomplete-form-option:disabled { + background: #FFD700; + color: rgba(7, 0, 99, 0.5); + cursor: not-allowed; + opacity: 0.7; + box-shadow: none; +} + +.task-flow-manager-extensions-popup-container .autocomplete-form-option:hover { + background: #FFC700; + font-weight: bold; +} + +.task-flow-manager-extensions-popup-container .tab-container { + display: none; +} + +.task-flow-manager-extensions-popup-container.expanded .tab-container { + display: block; + width: 100%; +} + +.task-flow-manager-extensions-popup-container .tab-button { + background-color: #f5f5f5; + border: none; + border-bottom: 2px solid transparent; + padding: 10px 20px; + cursor: pointer; + font-size: 14px; + width: 100%; + transition: background-color 0.2s ease, border-bottom 0.2s ease; +} + +.task-flow-manager-extensions-popup-container .autocomplete-icon-tooltip { + visibility: hidden; + position: absolute; + background-color: whitesmoke; + width: 300px; + border-radius: 6px; + transform: translate(-50%, -5%); + bottom: 100%; + padding: 10px 16px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); + transition: visibility 0.2s ease; + color: #333; +} + +.task-flow-manager-extensions-popup-container:hover .autocomplete-icon-tooltip { + visibility: visible; +} + +.task-flow-manager-extensions-popup-container .tab-button.selected { + background-color: transparent; + border-bottom: 2px solid #007bff; +} + +.task-flow-manager-extensions-popup-container .tab-content { + display: none; + padding: 15px; +} + +.task-flow-manager-extensions-popup-container .tab-content.active { + display: block; +} + +.email-list-container { + max-height: 150px; + overflow-y: auto; + border: 1px solid #ccc; + padding: 10px; + border-radius: 5px; + background-color: #f9f9f9; +} + +.email-item { + margin-bottom: 5px; + font-size: 14px; + cursor: pointer; +} + +.email-item:hover { + background-color: #e6e6e6; +} + +.tab-buttons-container { + display: flex; + width: 100%; +} + +/* TEXT AREA PROMPT */ +.context-textarea { + width: 100%; + height: 200px; + padding: 12px; + font-size: 16px; + line-height: 1.5; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + color: #333; + background-color: #f9f9f9; + border: 1px solid #ccc; + border-radius: 6px; + resize: none; + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.3) transparent; +} + +.context-textarea::-webkit-scrollbar { + width: 10px; +} + +.context-textarea::-webkit-scrollbar-track { + background: transparent; +} + +.context-textarea::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.3); + border-radius: 5px; + border: 2px solid transparent; + background-clip: content-box; +} + +.context-textarea:hover::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.5); +} + +.context-textarea:hover { + scrollbar-color: rgba(0, 0, 0, 0.5) transparent; +} + +/* TEXT AREA PROMPT */ + + +@keyframes spinCoin { + 0% { + transform: rotateY(0deg); + } + 100% { + transform: rotateY(360deg); + } +} diff --git a/idrocap_wa/webroot/js/init_tiny_mce.js b/idrocap_wa/webroot/js/init_tiny_mce.js new file mode 100644 index 0000000..86bc690 --- /dev/null +++ b/idrocap_wa/webroot/js/init_tiny_mce.js @@ -0,0 +1,62 @@ +const textAreaId = "#description"; +const tinyMceLangPath = '/js/tinymce/langs/it.js'; +const currentLocation = window.location.pathname; + +const privacyPaths = { + edit: '/privacy/edit', + view: '/privacy/view', + accept_privacy: '/privacy/accept_privacy', + view_public: '/privacy/view_public', +} + +const configs = { + [privacyPaths.edit]: { + selector: textAreaId, + language_url: tinyMceLangPath, + language: 'it', + setup: function (editor) { + editor.on('change', function () { + editor.save(); + }); + } + }, + [privacyPaths.view]: { + selector: textAreaId, + license_key: 'gpl', + language_url: tinyMceLangPath, + language: 'it', + readonly: true, + menubar: false, + toolbar: '', + height: 400, + }, + [privacyPaths.accept_privacy]: { + selector: textAreaId, + license_key: 'gpl', + language_url: tinyMceLangPath, + language: 'it', + readonly: true, + menubar: false, + toolbar: '', + height: 400 + }, + [privacyPaths.view_public]: { + selector: textAreaId, + license_key: 'gpl', + language_url: tinyMceLangPath, + language: 'it', + readonly: true, + menubar: false, + toolbar: '', + height: 400, + }, +}; + + +console.log(currentLocation); +const config = configs[currentLocation]; +if (config) { + tinymce.init(config); +} else { + console.error('No config found for current location'); +} diff --git a/idrocap_wa/webroot/js/jixel-primitives.js b/idrocap_wa/webroot/js/jixel-primitives.js new file mode 100644 index 0000000..a30e97e --- /dev/null +++ b/idrocap_wa/webroot/js/jixel-primitives.js @@ -0,0 +1,45 @@ +String.prototype.ununderscore = function () { return this.split('').map(char => char == '_' ? ' ' : char).join(''); }; + +var makeGetRequest = (url, options) => { + const headers = typeof options == 'object' ? options.headers : undefined; + const identifier = typeof options == 'object' ? options.identifier : undefined; + const request = new XMLHttpRequest(); + return new Promise((resolve, reject) => { + request.onreadystatechange = () => { + if (request.readyState !== 4) return; + if (request.status == 200) { + let response = request.responseText; + if (request.getResponseHeader('content-type').split('json').length == 2) { + try { + response = JSON.parse(request.responseText); + } + catch (error) { + reject({ + url: url, + status: 400, + statusText: error.message, + raw_response: request.responseText, + }); + } + } + identifier == undefined || (response = {identifier: identifier, response: response}); + resolve(response); + } else { + reject({ + url: url, + status: request.status, + statusText: request.statusText + }); + } + }; + request.open('GET', url); + if (typeof headers == 'object') { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + request.setRequestHeader(header, headers[header]); + } + } + } + request.send(); + }); +}; diff --git a/idrocap_wa/webroot/js/moment.js b/idrocap_wa/webroot/js/moment.js new file mode 100644 index 0000000..7998adb --- /dev/null +++ b/idrocap_wa/webroot/js/moment.js @@ -0,0 +1,5685 @@ +//! moment.js +//! version : 2.29.4 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + global.moment = factory() +}(this, (function () { 'use strict'; + + var hookCallback; + + function hooks() { + return hookCallback.apply(null, arguments); + } + + // This is done to register the method called with moment() + // without creating circular dependencies. + function setHookCallback(callback) { + hookCallback = callback; + } + + function isArray(input) { + return ( + input instanceof Array || + Object.prototype.toString.call(input) === '[object Array]' + ); + } + + function isObject(input) { + // IE8 will treat undefined and null as object if it wasn't for + // input != null + return ( + input != null && + Object.prototype.toString.call(input) === '[object Object]' + ); + } + + function hasOwnProp(a, b) { + return Object.prototype.hasOwnProperty.call(a, b); + } + + function isObjectEmpty(obj) { + if (Object.getOwnPropertyNames) { + return Object.getOwnPropertyNames(obj).length === 0; + } else { + var k; + for (k in obj) { + if (hasOwnProp(obj, k)) { + return false; + } + } + return true; + } + } + + function isUndefined(input) { + return input === void 0; + } + + function isNumber(input) { + return ( + typeof input === 'number' || + Object.prototype.toString.call(input) === '[object Number]' + ); + } + + function isDate(input) { + return ( + input instanceof Date || + Object.prototype.toString.call(input) === '[object Date]' + ); + } + + function map(arr, fn) { + var res = [], + i, + arrLen = arr.length; + for (i = 0; i < arrLen; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function createUTC(input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, true).utc(); + } + + function defaultParsingFlags() { + // We need to deep clone this object. + return { + empty: false, + unusedTokens: [], + unusedInput: [], + overflow: -2, + charsLeftOver: 0, + nullInput: false, + invalidEra: null, + invalidMonth: null, + invalidFormat: false, + userInvalidated: false, + iso: false, + parsedDateParts: [], + era: null, + meridiem: null, + rfc2822: false, + weekdayMismatch: false, + }; + } + + function getParsingFlags(m) { + if (m._pf == null) { + m._pf = defaultParsingFlags(); + } + return m._pf; + } + + var some; + if (Array.prototype.some) { + some = Array.prototype.some; + } else { + some = function (fun) { + var t = Object(this), + len = t.length >>> 0, + i; + + for (i = 0; i < len; i++) { + if (i in t && fun.call(this, t[i], i, t)) { + return true; + } + } + + return false; + }; + } + + function isValid(m) { + if (m._isValid == null) { + var flags = getParsingFlags(m), + parsedParts = some.call(flags.parsedDateParts, function (i) { + return i != null; + }), + isNowValid = + !isNaN(m._d.getTime()) && + flags.overflow < 0 && + !flags.empty && + !flags.invalidEra && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.weekdayMismatch && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated && + (!flags.meridiem || (flags.meridiem && parsedParts)); + + if (m._strict) { + isNowValid = + isNowValid && + flags.charsLeftOver === 0 && + flags.unusedTokens.length === 0 && + flags.bigHour === undefined; + } + + if (Object.isFrozen == null || !Object.isFrozen(m)) { + m._isValid = isNowValid; + } else { + return isNowValid; + } + } + return m._isValid; + } + + function createInvalid(flags) { + var m = createUTC(NaN); + if (flags != null) { + extend(getParsingFlags(m), flags); + } else { + getParsingFlags(m).userInvalidated = true; + } + + return m; + } + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + var momentProperties = (hooks.momentProperties = []), + updateInProgress = false; + + function copyConfig(to, from) { + var i, + prop, + val, + momentPropertiesLen = momentProperties.length; + + if (!isUndefined(from._isAMomentObject)) { + to._isAMomentObject = from._isAMomentObject; + } + if (!isUndefined(from._i)) { + to._i = from._i; + } + if (!isUndefined(from._f)) { + to._f = from._f; + } + if (!isUndefined(from._l)) { + to._l = from._l; + } + if (!isUndefined(from._strict)) { + to._strict = from._strict; + } + if (!isUndefined(from._tzm)) { + to._tzm = from._tzm; + } + if (!isUndefined(from._isUTC)) { + to._isUTC = from._isUTC; + } + if (!isUndefined(from._offset)) { + to._offset = from._offset; + } + if (!isUndefined(from._pf)) { + to._pf = getParsingFlags(from); + } + if (!isUndefined(from._locale)) { + to._locale = from._locale; + } + + if (momentPropertiesLen > 0) { + for (i = 0; i < momentPropertiesLen; i++) { + prop = momentProperties[i]; + val = from[prop]; + if (!isUndefined(val)) { + to[prop] = val; + } + } + } + + return to; + } + + // Moment prototype object + function Moment(config) { + copyConfig(this, config); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); + if (!this.isValid()) { + this._d = new Date(NaN); + } + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + hooks.updateOffset(this); + updateInProgress = false; + } + } + + function isMoment(obj) { + return ( + obj instanceof Moment || (obj != null && obj._isAMomentObject != null) + ); + } + + function warn(msg) { + if ( + hooks.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && + console.warn + ) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + + return extend(function () { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(null, msg); + } + if (firstTime) { + var args = [], + arg, + i, + key, + argLen = arguments.length; + for (i = 0; i < argLen; i++) { + arg = ''; + if (typeof arguments[i] === 'object') { + arg += '\n[' + i + '] '; + for (key in arguments[0]) { + if (hasOwnProp(arguments[0], key)) { + arg += key + ': ' + arguments[0][key] + ', '; + } + } + arg = arg.slice(0, -2); // Remove trailing comma and space + } else { + arg = arguments[i]; + } + args.push(arg); + } + warn( + msg + + '\nArguments: ' + + Array.prototype.slice.call(args).join('') + + '\n' + + new Error().stack + ); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + var deprecations = {}; + + function deprecateSimple(name, msg) { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(name, msg); + } + if (!deprecations[name]) { + warn(msg); + deprecations[name] = true; + } + } + + hooks.suppressDeprecationWarnings = false; + hooks.deprecationHandler = null; + + function isFunction(input) { + return ( + (typeof Function !== 'undefined' && input instanceof Function) || + Object.prototype.toString.call(input) === '[object Function]' + ); + } + + function set(config) { + var prop, i; + for (i in config) { + if (hasOwnProp(config, i)) { + prop = config[i]; + if (isFunction(prop)) { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + } + this._config = config; + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _dayOfMonthOrdinalParse. + // TODO: Remove "ordinalParse" fallback in next major release. + this._dayOfMonthOrdinalParseLenient = new RegExp( + (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + + '|' + + /\d{1,2}/.source + ); + } + + function mergeConfigs(parentConfig, childConfig) { + var res = extend({}, parentConfig), + prop; + for (prop in childConfig) { + if (hasOwnProp(childConfig, prop)) { + if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { + res[prop] = {}; + extend(res[prop], parentConfig[prop]); + extend(res[prop], childConfig[prop]); + } else if (childConfig[prop] != null) { + res[prop] = childConfig[prop]; + } else { + delete res[prop]; + } + } + } + for (prop in parentConfig) { + if ( + hasOwnProp(parentConfig, prop) && + !hasOwnProp(childConfig, prop) && + isObject(parentConfig[prop]) + ) { + // make sure changes to properties don't modify parent config + res[prop] = extend({}, res[prop]); + } + } + return res; + } + + function Locale(config) { + if (config != null) { + this.set(config); + } + } + + var keys; + + if (Object.keys) { + keys = Object.keys; + } else { + keys = function (obj) { + var i, + res = []; + for (i in obj) { + if (hasOwnProp(obj, i)) { + res.push(i); + } + } + return res; + }; + } + + var defaultCalendar = { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }; + + function calendar(key, mom, now) { + var output = this._calendar[key] || this._calendar['sameElse']; + return isFunction(output) ? output.call(mom, now) : output; + } + + function zeroFill(number, targetLength, forceSign) { + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, + sign = number >= 0; + return ( + (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + + absNumber + ); + } + + var formattingTokens = + /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, + formatFunctions = {}, + formatTokenFunctions = {}; + + // token: 'M' + // padded: ['MM', 2] + // ordinal: 'Mo' + // callback: function () { this.month() + 1 } + function addFormatToken(token, padded, ordinal, callback) { + var func = callback; + if (typeof callback === 'string') { + func = function () { + return this[callback](); + }; + } + if (token) { + formatTokenFunctions[token] = func; + } + if (padded) { + formatTokenFunctions[padded[0]] = function () { + return zeroFill(func.apply(this, arguments), padded[1], padded[2]); + }; + } + if (ordinal) { + formatTokenFunctions[ordinal] = function () { + return this.localeData().ordinal( + func.apply(this, arguments), + token + ); + }; + } + } + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), + i, + length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = '', + i; + for (i = 0; i < length; i++) { + output += isFunction(array[i]) + ? array[i].call(mom, format) + : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + formatFunctions[format] = + formatFunctions[format] || makeFormatFunction(format); + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace( + localFormattingTokens, + replaceLongDateFormatTokens + ); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + var defaultLongDateFormat = { + LTS: 'h:mm:ss A', + LT: 'h:mm A', + L: 'MM/DD/YYYY', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY h:mm A', + LLLL: 'dddd, MMMM D, YYYY h:mm A', + }; + + function longDateFormat(key) { + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + this._longDateFormat[key] = formatUpper + .match(formattingTokens) + .map(function (tok) { + if ( + tok === 'MMMM' || + tok === 'MM' || + tok === 'DD' || + tok === 'dddd' + ) { + return tok.slice(1); + } + return tok; + }) + .join(''); + + return this._longDateFormat[key]; + } + + var defaultInvalidDate = 'Invalid date'; + + function invalidDate() { + return this._invalidDate; + } + + var defaultOrdinal = '%d', + defaultDayOfMonthOrdinalParse = /\d{1,2}/; + + function ordinal(number) { + return this._ordinal.replace('%d', number); + } + + var defaultRelativeTime = { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + w: 'a week', + ww: '%d weeks', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }; + + function relativeTime(number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return isFunction(output) + ? output(number, withoutSuffix, string, isFuture) + : output.replace(/%d/i, number); + } + + function pastFuture(diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return isFunction(format) ? format(output) : format.replace(/%s/i, output); + } + + var aliases = {}; + + function addUnitAlias(unit, shorthand) { + var lowerCase = unit.toLowerCase(); + aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; + } + + function normalizeUnits(units) { + return typeof units === 'string' + ? aliases[units] || aliases[units.toLowerCase()] + : undefined; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + var priorities = {}; + + function addUnitPriority(unit, priority) { + priorities[unit] = priority; + } + + function getPrioritizedUnits(unitsObj) { + var units = [], + u; + for (u in unitsObj) { + if (hasOwnProp(unitsObj, u)) { + units.push({ unit: u, priority: priorities[u] }); + } + } + units.sort(function (a, b) { + return a.priority - b.priority; + }); + return units; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function absFloor(number) { + if (number < 0) { + // -0 -> 0 + return Math.ceil(number) || 0; + } else { + return Math.floor(number); + } + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; + } + + function makeGetSet(unit, keepTime) { + return function (value) { + if (value != null) { + set$1(this, unit, value); + hooks.updateOffset(this, keepTime); + return this; + } else { + return get(this, unit); + } + }; + } + + function get(mom, unit) { + return mom.isValid() + ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() + : NaN; + } + + function set$1(mom, unit, value) { + if (mom.isValid() && !isNaN(value)) { + if ( + unit === 'FullYear' && + isLeapYear(mom.year()) && + mom.month() === 1 && + mom.date() === 29 + ) { + value = toInt(value); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit]( + value, + mom.month(), + daysInMonth(value, mom.month()) + ); + } else { + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + } + + // MOMENTS + + function stringGet(units) { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](); + } + return this; + } + + function stringSet(units, value) { + if (typeof units === 'object') { + units = normalizeObjectUnits(units); + var prioritized = getPrioritizedUnits(units), + i, + prioritizedLen = prioritized.length; + for (i = 0; i < prioritizedLen; i++) { + this[prioritized[i].unit](units[prioritized[i].unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; + } + + var match1 = /\d/, // 0 - 9 + match2 = /\d\d/, // 00 - 99 + match3 = /\d{3}/, // 000 - 999 + match4 = /\d{4}/, // 0000 - 9999 + match6 = /[+-]?\d{6}/, // -999999 - 999999 + match1to2 = /\d\d?/, // 0 - 99 + match3to4 = /\d\d\d\d?/, // 999 - 9999 + match5to6 = /\d\d\d\d\d\d?/, // 99999 - 999999 + match1to3 = /\d{1,3}/, // 0 - 999 + match1to4 = /\d{1,4}/, // 0 - 9999 + match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999 + matchUnsigned = /\d+/, // 0 - inf + matchSigned = /[+-]?\d+/, // -inf - inf + matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z + matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + // any word (or two) characters or numbers including two/three word month in arabic. + // includes scottish gaelic two word and hyphenated months + matchWord = + /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, + regexes; + + regexes = {}; + + function addRegexToken(token, regex, strictRegex) { + regexes[token] = isFunction(regex) + ? regex + : function (isStrict, localeData) { + return isStrict && strictRegex ? strictRegex : regex; + }; + } + + function getParseRegexForToken(token, config) { + if (!hasOwnProp(regexes, token)) { + return new RegExp(unescapeFormat(token)); + } + + return regexes[token](config._strict, config._locale); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function unescapeFormat(s) { + return regexEscape( + s + .replace('\\', '') + .replace( + /\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, + function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + } + ) + ); + } + + function regexEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + var tokens = {}; + + function addParseToken(token, callback) { + var i, + func = callback, + tokenLen; + if (typeof token === 'string') { + token = [token]; + } + if (isNumber(callback)) { + func = function (input, array) { + array[callback] = toInt(input); + }; + } + tokenLen = token.length; + for (i = 0; i < tokenLen; i++) { + tokens[token[i]] = func; + } + } + + function addWeekParseToken(token, callback) { + addParseToken(token, function (input, array, config, token) { + config._w = config._w || {}; + callback(input, config._w, config, token); + }); + } + + function addTimeToArrayFromToken(token, input, config) { + if (input != null && hasOwnProp(tokens, token)) { + tokens[token](input, config._a, config, token); + } + } + + var YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + WEEK = 7, + WEEKDAY = 8; + + function mod(n, x) { + return ((n % x) + x) % x; + } + + var indexOf; + + if (Array.prototype.indexOf) { + indexOf = Array.prototype.indexOf; + } else { + indexOf = function (o) { + // I know + var i; + for (i = 0; i < this.length; ++i) { + if (this[i] === o) { + return i; + } + } + return -1; + }; + } + + function daysInMonth(year, month) { + if (isNaN(year) || isNaN(month)) { + return NaN; + } + var modMonth = mod(month, 12); + year += (month - modMonth) / 12; + return modMonth === 1 + ? isLeapYear(year) + ? 29 + : 28 + : 31 - ((modMonth % 7) % 2); + } + + // FORMATTING + + addFormatToken('M', ['MM', 2], 'Mo', function () { + return this.month() + 1; + }); + + addFormatToken('MMM', 0, 0, function (format) { + return this.localeData().monthsShort(this, format); + }); + + addFormatToken('MMMM', 0, 0, function (format) { + return this.localeData().months(this, format); + }); + + // ALIASES + + addUnitAlias('month', 'M'); + + // PRIORITY + + addUnitPriority('month', 8); + + // PARSING + + addRegexToken('M', match1to2); + addRegexToken('MM', match1to2, match2); + addRegexToken('MMM', function (isStrict, locale) { + return locale.monthsShortRegex(isStrict); + }); + addRegexToken('MMMM', function (isStrict, locale) { + return locale.monthsRegex(isStrict); + }); + + addParseToken(['M', 'MM'], function (input, array) { + array[MONTH] = toInt(input) - 1; + }); + + addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { + var month = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (month != null) { + array[MONTH] = month; + } else { + getParsingFlags(config).invalidMonth = input; + } + }); + + // LOCALES + + var defaultLocaleMonths = + 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + defaultLocaleMonthsShort = + 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, + defaultMonthsShortRegex = matchWord, + defaultMonthsRegex = matchWord; + + function localeMonths(m, format) { + if (!m) { + return isArray(this._months) + ? this._months + : this._months['standalone']; + } + return isArray(this._months) + ? this._months[m.month()] + : this._months[ + (this._months.isFormat || MONTHS_IN_FORMAT).test(format) + ? 'format' + : 'standalone' + ][m.month()]; + } + + function localeMonthsShort(m, format) { + if (!m) { + return isArray(this._monthsShort) + ? this._monthsShort + : this._monthsShort['standalone']; + } + return isArray(this._monthsShort) + ? this._monthsShort[m.month()] + : this._monthsShort[ + MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone' + ][m.month()]; + } + + function handleStrictParse(monthName, format, strict) { + var i, + ii, + mom, + llc = monthName.toLocaleLowerCase(); + if (!this._monthsParse) { + // this is not used + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + for (i = 0; i < 12; ++i) { + mom = createUTC([2000, i]); + this._shortMonthsParse[i] = this.monthsShort( + mom, + '' + ).toLocaleLowerCase(); + this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'MMM') { + ii = indexOf.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'MMM') { + ii = indexOf.call(this._shortMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._longMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } + } + + function localeMonthsParse(monthName, format, strict) { + var i, mom, regex; + + if (this._monthsParseExact) { + return handleStrictParse.call(this, monthName, format, strict); + } + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + // TODO: add sorting + // Sorting makes sure if one month (or abbr) is a prefix of another + // see sorting in computeMonthsParse + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp( + '^' + this.months(mom, '').replace('.', '') + '$', + 'i' + ); + this._shortMonthsParse[i] = new RegExp( + '^' + this.monthsShort(mom, '').replace('.', '') + '$', + 'i' + ); + } + if (!strict && !this._monthsParse[i]) { + regex = + '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if ( + strict && + format === 'MMMM' && + this._longMonthsParse[i].test(monthName) + ) { + return i; + } else if ( + strict && + format === 'MMM' && + this._shortMonthsParse[i].test(monthName) + ) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + } + + // MOMENTS + + function setMonth(mom, value) { + var dayOfMonth; + + if (!mom.isValid()) { + // No op + return mom; + } + + if (typeof value === 'string') { + if (/^\d+$/.test(value)) { + value = toInt(value); + } else { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (!isNumber(value)) { + return mom; + } + } + } + + dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function getSetMonth(value) { + if (value != null) { + setMonth(this, value); + hooks.updateOffset(this, true); + return this; + } else { + return get(this, 'Month'); + } + } + + function getDaysInMonth() { + return daysInMonth(this.year(), this.month()); + } + + function monthsShortRegex(isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsShortStrictRegex; + } else { + return this._monthsShortRegex; + } + } else { + if (!hasOwnProp(this, '_monthsShortRegex')) { + this._monthsShortRegex = defaultMonthsShortRegex; + } + return this._monthsShortStrictRegex && isStrict + ? this._monthsShortStrictRegex + : this._monthsShortRegex; + } + } + + function monthsRegex(isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsStrictRegex; + } else { + return this._monthsRegex; + } + } else { + if (!hasOwnProp(this, '_monthsRegex')) { + this._monthsRegex = defaultMonthsRegex; + } + return this._monthsStrictRegex && isStrict + ? this._monthsStrictRegex + : this._monthsRegex; + } + } + + function computeMonthsParse() { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var shortPieces = [], + longPieces = [], + mixedPieces = [], + i, + mom; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + shortPieces.push(this.monthsShort(mom, '')); + longPieces.push(this.months(mom, '')); + mixedPieces.push(this.months(mom, '')); + mixedPieces.push(this.monthsShort(mom, '')); + } + // Sorting makes sure if one month (or abbr) is a prefix of another it + // will match the longer piece. + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 12; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + } + for (i = 0; i < 24; i++) { + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._monthsShortRegex = this._monthsRegex; + this._monthsStrictRegex = new RegExp( + '^(' + longPieces.join('|') + ')', + 'i' + ); + this._monthsShortStrictRegex = new RegExp( + '^(' + shortPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? zeroFill(y, 4) : '+' + y; + }); + + addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; + }); + + addFormatToken(0, ['YYYY', 4], 0, 'year'); + addFormatToken(0, ['YYYYY', 5], 0, 'year'); + addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + + // ALIASES + + addUnitAlias('year', 'y'); + + // PRIORITIES + + addUnitPriority('year', 1); + + // PARSING + + addRegexToken('Y', matchSigned); + addRegexToken('YY', match1to2, match2); + addRegexToken('YYYY', match1to4, match4); + addRegexToken('YYYYY', match1to6, match6); + addRegexToken('YYYYYY', match1to6, match6); + + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = + input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); + }); + addParseToken('YY', function (input, array) { + array[YEAR] = hooks.parseTwoDigitYear(input); + }); + addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); + }); + + // HELPERS + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + // HOOKS + + hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + // MOMENTS + + var getSetYear = makeGetSet('FullYear', true); + + function getIsLeapYear() { + return isLeapYear(this.year()); + } + + function createDate(y, m, d, h, M, s, ms) { + // can't just apply() to create a date: + // https://stackoverflow.com/q/181348 + var date; + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + date = new Date(y + 400, m, d, h, M, s, ms); + if (isFinite(date.getFullYear())) { + date.setFullYear(y); + } + } else { + date = new Date(y, m, d, h, M, s, ms); + } + + return date; + } + + function createUTCDate(y) { + var date, args; + // the Date.UTC function remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + args = Array.prototype.slice.call(arguments); + // preserve leap years using a full 400 year cycle, then reset + args[0] = y + 400; + date = new Date(Date.UTC.apply(null, args)); + if (isFinite(date.getUTCFullYear())) { + date.setUTCFullYear(y); + } + } else { + date = new Date(Date.UTC.apply(null, arguments)); + } + + return date; + } + + // start-of-first-week - start-of-year + function firstWeekOffset(year, dow, doy) { + var // first-week day -- which january is always in the first week (4 for iso, 1 for other) + fwd = 7 + dow - doy, + // first-week day local weekday -- which local weekday is fwd + fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + + return -fwdlw + fwd - 1; + } + + // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, dow, doy) { + var localWeekday = (7 + weekday - dow) % 7, + weekOffset = firstWeekOffset(year, dow, doy), + dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, + resYear, + resDayOfYear; + + if (dayOfYear <= 0) { + resYear = year - 1; + resDayOfYear = daysInYear(resYear) + dayOfYear; + } else if (dayOfYear > daysInYear(year)) { + resYear = year + 1; + resDayOfYear = dayOfYear - daysInYear(year); + } else { + resYear = year; + resDayOfYear = dayOfYear; + } + + return { + year: resYear, + dayOfYear: resDayOfYear, + }; + } + + function weekOfYear(mom, dow, doy) { + var weekOffset = firstWeekOffset(mom.year(), dow, doy), + week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, + resWeek, + resYear; + + if (week < 1) { + resYear = mom.year() - 1; + resWeek = week + weeksInYear(resYear, dow, doy); + } else if (week > weeksInYear(mom.year(), dow, doy)) { + resWeek = week - weeksInYear(mom.year(), dow, doy); + resYear = mom.year() + 1; + } else { + resYear = mom.year(); + resWeek = week; + } + + return { + week: resWeek, + year: resYear, + }; + } + + function weeksInYear(year, dow, doy) { + var weekOffset = firstWeekOffset(year, dow, doy), + weekOffsetNext = firstWeekOffset(year + 1, dow, doy); + return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; + } + + // FORMATTING + + addFormatToken('w', ['ww', 2], 'wo', 'week'); + addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); + + // ALIASES + + addUnitAlias('week', 'w'); + addUnitAlias('isoWeek', 'W'); + + // PRIORITIES + + addUnitPriority('week', 5); + addUnitPriority('isoWeek', 5); + + // PARSING + + addRegexToken('w', match1to2); + addRegexToken('ww', match1to2, match2); + addRegexToken('W', match1to2); + addRegexToken('WW', match1to2, match2); + + addWeekParseToken( + ['w', 'ww', 'W', 'WW'], + function (input, week, config, token) { + week[token.substr(0, 1)] = toInt(input); + } + ); + + // HELPERS + + // LOCALES + + function localeWeek(mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + } + + var defaultLocaleWeek = { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }; + + function localeFirstDayOfWeek() { + return this._week.dow; + } + + function localeFirstDayOfYear() { + return this._week.doy; + } + + // MOMENTS + + function getSetWeek(input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + function getSetISOWeek(input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + // FORMATTING + + addFormatToken('d', 0, 'do', 'day'); + + addFormatToken('dd', 0, 0, function (format) { + return this.localeData().weekdaysMin(this, format); + }); + + addFormatToken('ddd', 0, 0, function (format) { + return this.localeData().weekdaysShort(this, format); + }); + + addFormatToken('dddd', 0, 0, function (format) { + return this.localeData().weekdays(this, format); + }); + + addFormatToken('e', 0, 0, 'weekday'); + addFormatToken('E', 0, 0, 'isoWeekday'); + + // ALIASES + + addUnitAlias('day', 'd'); + addUnitAlias('weekday', 'e'); + addUnitAlias('isoWeekday', 'E'); + + // PRIORITY + addUnitPriority('day', 11); + addUnitPriority('weekday', 11); + addUnitPriority('isoWeekday', 11); + + // PARSING + + addRegexToken('d', match1to2); + addRegexToken('e', match1to2); + addRegexToken('E', match1to2); + addRegexToken('dd', function (isStrict, locale) { + return locale.weekdaysMinRegex(isStrict); + }); + addRegexToken('ddd', function (isStrict, locale) { + return locale.weekdaysShortRegex(isStrict); + }); + addRegexToken('dddd', function (isStrict, locale) { + return locale.weekdaysRegex(isStrict); + }); + + addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { + var weekday = config._locale.weekdaysParse(input, token, config._strict); + // if we didn't get a weekday name, mark the date as invalid + if (weekday != null) { + week.d = weekday; + } else { + getParsingFlags(config).invalidWeekday = input; + } + }); + + addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { + week[token] = toInt(input); + }); + + // HELPERS + + function parseWeekday(input, locale) { + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; + } + + return null; + } + + function parseIsoWeekday(input, locale) { + if (typeof input === 'string') { + return locale.weekdaysParse(input) % 7 || 7; + } + return isNaN(input) ? null : input; + } + + // LOCALES + function shiftWeekdays(ws, n) { + return ws.slice(n, 7).concat(ws.slice(0, n)); + } + + var defaultLocaleWeekdays = + 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + defaultWeekdaysRegex = matchWord, + defaultWeekdaysShortRegex = matchWord, + defaultWeekdaysMinRegex = matchWord; + + function localeWeekdays(m, format) { + var weekdays = isArray(this._weekdays) + ? this._weekdays + : this._weekdays[ + m && m !== true && this._weekdays.isFormat.test(format) + ? 'format' + : 'standalone' + ]; + return m === true + ? shiftWeekdays(weekdays, this._week.dow) + : m + ? weekdays[m.day()] + : weekdays; + } + + function localeWeekdaysShort(m) { + return m === true + ? shiftWeekdays(this._weekdaysShort, this._week.dow) + : m + ? this._weekdaysShort[m.day()] + : this._weekdaysShort; + } + + function localeWeekdaysMin(m) { + return m === true + ? shiftWeekdays(this._weekdaysMin, this._week.dow) + : m + ? this._weekdaysMin[m.day()] + : this._weekdaysMin; + } + + function handleStrictParse$1(weekdayName, format, strict) { + var i, + ii, + mom, + llc = weekdayName.toLocaleLowerCase(); + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._shortWeekdaysParse = []; + this._minWeekdaysParse = []; + + for (i = 0; i < 7; ++i) { + mom = createUTC([2000, 1]).day(i); + this._minWeekdaysParse[i] = this.weekdaysMin( + mom, + '' + ).toLocaleLowerCase(); + this._shortWeekdaysParse[i] = this.weekdaysShort( + mom, + '' + ).toLocaleLowerCase(); + this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'dddd') { + ii = indexOf.call(this._weekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'dddd') { + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._minWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } + } + + function localeWeekdaysParse(weekdayName, format, strict) { + var i, mom, regex; + + if (this._weekdaysParseExact) { + return handleStrictParse$1.call(this, weekdayName, format, strict); + } + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._minWeekdaysParse = []; + this._shortWeekdaysParse = []; + this._fullWeekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + + mom = createUTC([2000, 1]).day(i); + if (strict && !this._fullWeekdaysParse[i]) { + this._fullWeekdaysParse[i] = new RegExp( + '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + this._shortWeekdaysParse[i] = new RegExp( + '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + this._minWeekdaysParse[i] = new RegExp( + '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + } + if (!this._weekdaysParse[i]) { + regex = + '^' + + this.weekdays(mom, '') + + '|^' + + this.weekdaysShort(mom, '') + + '|^' + + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if ( + strict && + format === 'dddd' && + this._fullWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if ( + strict && + format === 'ddd' && + this._shortWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if ( + strict && + format === 'dd' && + this._minWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + } + + // MOMENTS + + function getSetDayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + } + + function getSetLocaleDayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + } + + function getSetISODayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + + if (input != null) { + var weekday = parseIsoWeekday(input, this.localeData()); + return this.day(this.day() % 7 ? weekday : weekday - 7); + } else { + return this.day() || 7; + } + } + + function weekdaysRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysStrictRegex; + } else { + return this._weekdaysRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysRegex')) { + this._weekdaysRegex = defaultWeekdaysRegex; + } + return this._weekdaysStrictRegex && isStrict + ? this._weekdaysStrictRegex + : this._weekdaysRegex; + } + } + + function weekdaysShortRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysShortStrictRegex; + } else { + return this._weekdaysShortRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysShortRegex')) { + this._weekdaysShortRegex = defaultWeekdaysShortRegex; + } + return this._weekdaysShortStrictRegex && isStrict + ? this._weekdaysShortStrictRegex + : this._weekdaysShortRegex; + } + } + + function weekdaysMinRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysMinStrictRegex; + } else { + return this._weekdaysMinRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysMinRegex')) { + this._weekdaysMinRegex = defaultWeekdaysMinRegex; + } + return this._weekdaysMinStrictRegex && isStrict + ? this._weekdaysMinStrictRegex + : this._weekdaysMinRegex; + } + } + + function computeWeekdaysParse() { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var minPieces = [], + shortPieces = [], + longPieces = [], + mixedPieces = [], + i, + mom, + minp, + shortp, + longp; + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, 1]).day(i); + minp = regexEscape(this.weekdaysMin(mom, '')); + shortp = regexEscape(this.weekdaysShort(mom, '')); + longp = regexEscape(this.weekdays(mom, '')); + minPieces.push(minp); + shortPieces.push(shortp); + longPieces.push(longp); + mixedPieces.push(minp); + mixedPieces.push(shortp); + mixedPieces.push(longp); + } + // Sorting makes sure if one weekday (or abbr) is a prefix of another it + // will match the longer piece. + minPieces.sort(cmpLenRev); + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + + this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._weekdaysShortRegex = this._weekdaysRegex; + this._weekdaysMinRegex = this._weekdaysRegex; + + this._weekdaysStrictRegex = new RegExp( + '^(' + longPieces.join('|') + ')', + 'i' + ); + this._weekdaysShortStrictRegex = new RegExp( + '^(' + shortPieces.join('|') + ')', + 'i' + ); + this._weekdaysMinStrictRegex = new RegExp( + '^(' + minPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + function hFormat() { + return this.hours() % 12 || 12; + } + + function kFormat() { + return this.hours() || 24; + } + + addFormatToken('H', ['HH', 2], 0, 'hour'); + addFormatToken('h', ['hh', 2], 0, hFormat); + addFormatToken('k', ['kk', 2], 0, kFormat); + + addFormatToken('hmm', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); + }); + + addFormatToken('hmmss', 0, 0, function () { + return ( + '' + + hFormat.apply(this) + + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2) + ); + }); + + addFormatToken('Hmm', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2); + }); + + addFormatToken('Hmmss', 0, 0, function () { + return ( + '' + + this.hours() + + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2) + ); + }); + + function meridiem(token, lowercase) { + addFormatToken(token, 0, 0, function () { + return this.localeData().meridiem( + this.hours(), + this.minutes(), + lowercase + ); + }); + } + + meridiem('a', true); + meridiem('A', false); + + // ALIASES + + addUnitAlias('hour', 'h'); + + // PRIORITY + addUnitPriority('hour', 13); + + // PARSING + + function matchMeridiem(isStrict, locale) { + return locale._meridiemParse; + } + + addRegexToken('a', matchMeridiem); + addRegexToken('A', matchMeridiem); + addRegexToken('H', match1to2); + addRegexToken('h', match1to2); + addRegexToken('k', match1to2); + addRegexToken('HH', match1to2, match2); + addRegexToken('hh', match1to2, match2); + addRegexToken('kk', match1to2, match2); + + addRegexToken('hmm', match3to4); + addRegexToken('hmmss', match5to6); + addRegexToken('Hmm', match3to4); + addRegexToken('Hmmss', match5to6); + + addParseToken(['H', 'HH'], HOUR); + addParseToken(['k', 'kk'], function (input, array, config) { + var kInput = toInt(input); + array[HOUR] = kInput === 24 ? 0 : kInput; + }); + addParseToken(['a', 'A'], function (input, array, config) { + config._isPm = config._locale.isPM(input); + config._meridiem = input; + }); + addParseToken(['h', 'hh'], function (input, array, config) { + array[HOUR] = toInt(input); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmmss', function (input, array, config) { + var pos1 = input.length - 4, + pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('Hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + }); + addParseToken('Hmmss', function (input, array, config) { + var pos1 = input.length - 4, + pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + }); + + // LOCALES + + function localeIsPM(input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return (input + '').toLowerCase().charAt(0) === 'p'; + } + + var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i, + // Setting the hour should keep the time, because the user explicitly + // specified which hour they want. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + getSetHour = makeGetSet('Hours', true); + + function localeMeridiem(hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + } + + var baseConfig = { + calendar: defaultCalendar, + longDateFormat: defaultLongDateFormat, + invalidDate: defaultInvalidDate, + ordinal: defaultOrdinal, + dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, + relativeTime: defaultRelativeTime, + + months: defaultLocaleMonths, + monthsShort: defaultLocaleMonthsShort, + + week: defaultLocaleWeek, + + weekdays: defaultLocaleWeekdays, + weekdaysMin: defaultLocaleWeekdaysMin, + weekdaysShort: defaultLocaleWeekdaysShort, + + meridiemParse: defaultLocaleMeridiemParse, + }; + + // internal storage for locale config files + var locales = {}, + localeFamilies = {}, + globalLocale; + + function commonPrefix(arr1, arr2) { + var i, + minl = Math.min(arr1.length, arr2.length); + for (i = 0; i < minl; i += 1) { + if (arr1[i] !== arr2[i]) { + return i; + } + } + return minl; + } + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, + j, + next, + locale, + split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if ( + next && + next.length >= j && + commonPrefix(split, next) >= j - 1 + ) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return globalLocale; + } + + function isLocaleNameSane(name) { + // Prevent names that look like filesystem paths, i.e contain '/' or '\' + return name.match('^[^/\\\\]*$') != null; + } + + function loadLocale(name) { + var oldLocale = null, + aliasedRequire; + // TODO: Find a better way to register and load all the locales in Node + if ( + locales[name] === undefined && + typeof module !== 'undefined' && + module && + module.exports && + isLocaleNameSane(name) + ) { + try { + oldLocale = globalLocale._abbr; + aliasedRequire = require; + aliasedRequire('./locale/' + name); + getSetGlobalLocale(oldLocale); + } catch (e) { + // mark as not found to avoid repeating expensive file require call causing high CPU + // when trying to find en-US, en_US, en-us for every format call + locales[name] = null; // null means not found + } + } + return locales[name]; + } + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + function getSetGlobalLocale(key, values) { + var data; + if (key) { + if (isUndefined(values)) { + data = getLocale(key); + } else { + data = defineLocale(key, values); + } + + if (data) { + // moment.duration._locale = moment._locale = data; + globalLocale = data; + } else { + if (typeof console !== 'undefined' && console.warn) { + //warn user if arguments are passed but the locale could not be set + console.warn( + 'Locale ' + key + ' not found. Did you forget to load it?' + ); + } + } + } + + return globalLocale._abbr; + } + + function defineLocale(name, config) { + if (config !== null) { + var locale, + parentConfig = baseConfig; + config.abbr = name; + if (locales[name] != null) { + deprecateSimple( + 'defineLocaleOverride', + 'use moment.updateLocale(localeName, config) to change ' + + 'an existing locale. moment.defineLocale(localeName, ' + + 'config) should only be used for creating a new locale ' + + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.' + ); + parentConfig = locales[name]._config; + } else if (config.parentLocale != null) { + if (locales[config.parentLocale] != null) { + parentConfig = locales[config.parentLocale]._config; + } else { + locale = loadLocale(config.parentLocale); + if (locale != null) { + parentConfig = locale._config; + } else { + if (!localeFamilies[config.parentLocale]) { + localeFamilies[config.parentLocale] = []; + } + localeFamilies[config.parentLocale].push({ + name: name, + config: config, + }); + return null; + } + } + } + locales[name] = new Locale(mergeConfigs(parentConfig, config)); + + if (localeFamilies[name]) { + localeFamilies[name].forEach(function (x) { + defineLocale(x.name, x.config); + }); + } + + // backwards compat for now: also set the locale + // make sure we set the locale AFTER all child locales have been + // created, so we won't end up with the child locale set. + getSetGlobalLocale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + } + + function updateLocale(name, config) { + if (config != null) { + var locale, + tmpLocale, + parentConfig = baseConfig; + + if (locales[name] != null && locales[name].parentLocale != null) { + // Update existing child locale in-place to avoid memory-leaks + locales[name].set(mergeConfigs(locales[name]._config, config)); + } else { + // MERGE + tmpLocale = loadLocale(name); + if (tmpLocale != null) { + parentConfig = tmpLocale._config; + } + config = mergeConfigs(parentConfig, config); + if (tmpLocale == null) { + // updateLocale is called for creating a new locale + // Set abbr so it will have a name (getters return + // undefined otherwise). + config.abbr = name; + } + locale = new Locale(config); + locale.parentLocale = locales[name]; + locales[name] = locale; + } + + // backwards compat for now: also set the locale + getSetGlobalLocale(name); + } else { + // pass null for config to unupdate, useful for tests + if (locales[name] != null) { + if (locales[name].parentLocale != null) { + locales[name] = locales[name].parentLocale; + if (name === getSetGlobalLocale()) { + getSetGlobalLocale(name); + } + } else if (locales[name] != null) { + delete locales[name]; + } + } + } + return locales[name]; + } + + // returns locale data + function getLocale(key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return globalLocale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + } + + function listLocales() { + return keys(locales); + } + + function checkOverflow(m) { + var overflow, + a = m._a; + + if (a && getParsingFlags(m).overflow === -2) { + overflow = + a[MONTH] < 0 || a[MONTH] > 11 + ? MONTH + : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) + ? DATE + : a[HOUR] < 0 || + a[HOUR] > 24 || + (a[HOUR] === 24 && + (a[MINUTE] !== 0 || + a[SECOND] !== 0 || + a[MILLISECOND] !== 0)) + ? HOUR + : a[MINUTE] < 0 || a[MINUTE] > 59 + ? MINUTE + : a[SECOND] < 0 || a[SECOND] > 59 + ? SECOND + : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 + ? MILLISECOND + : -1; + + if ( + getParsingFlags(m)._overflowDayOfYear && + (overflow < YEAR || overflow > DATE) + ) { + overflow = DATE; + } + if (getParsingFlags(m)._overflowWeeks && overflow === -1) { + overflow = WEEK; + } + if (getParsingFlags(m)._overflowWeekday && overflow === -1) { + overflow = WEEKDAY; + } + + getParsingFlags(m).overflow = overflow; + } + + return m; + } + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + var extendedIsoRegex = + /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + basicIsoRegex = + /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + tzRegex = /Z|[+-]\d\d(?::?\d\d)?/, + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], + ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], + ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], + ['GGGG-[W]WW', /\d{4}-W\d\d/, false], + ['YYYY-DDD', /\d{4}-\d{3}/], + ['YYYY-MM', /\d{4}-\d\d/, false], + ['YYYYYYMMDD', /[+-]\d{10}/], + ['YYYYMMDD', /\d{8}/], + ['GGGG[W]WWE', /\d{4}W\d{3}/], + ['GGGG[W]WW', /\d{4}W\d{2}/, false], + ['YYYYDDD', /\d{7}/], + ['YYYYMM', /\d{6}/, false], + ['YYYY', /\d{4}/, false], + ], + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], + ['HH:mm:ss', /\d\d:\d\d:\d\d/], + ['HH:mm', /\d\d:\d\d/], + ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], + ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], + ['HHmmss', /\d\d\d\d\d\d/], + ['HHmm', /\d\d\d\d/], + ['HH', /\d\d/], + ], + aspNetJsonRegex = /^\/?Date\((-?\d+)/i, + // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 + rfc2822 = + /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, + obsOffsets = { + UT: 0, + GMT: 0, + EDT: -4 * 60, + EST: -5 * 60, + CDT: -5 * 60, + CST: -6 * 60, + MDT: -6 * 60, + MST: -7 * 60, + PDT: -7 * 60, + PST: -8 * 60, + }; + + // date from iso format + function configFromISO(config) { + var i, + l, + string = config._i, + match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), + allowTime, + dateFormat, + timeFormat, + tzFormat, + isoDatesLen = isoDates.length, + isoTimesLen = isoTimes.length; + + if (match) { + getParsingFlags(config).iso = true; + for (i = 0, l = isoDatesLen; i < l; i++) { + if (isoDates[i][1].exec(match[1])) { + dateFormat = isoDates[i][0]; + allowTime = isoDates[i][2] !== false; + break; + } + } + if (dateFormat == null) { + config._isValid = false; + return; + } + if (match[3]) { + for (i = 0, l = isoTimesLen; i < l; i++) { + if (isoTimes[i][1].exec(match[3])) { + // match[2] should be 'T' or space + timeFormat = (match[2] || ' ') + isoTimes[i][0]; + break; + } + } + if (timeFormat == null) { + config._isValid = false; + return; + } + } + if (!allowTime && timeFormat != null) { + config._isValid = false; + return; + } + if (match[4]) { + if (tzRegex.exec(match[4])) { + tzFormat = 'Z'; + } else { + config._isValid = false; + return; + } + } + config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); + configFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + function extractFromRFC2822Strings( + yearStr, + monthStr, + dayStr, + hourStr, + minuteStr, + secondStr + ) { + var result = [ + untruncateYear(yearStr), + defaultLocaleMonthsShort.indexOf(monthStr), + parseInt(dayStr, 10), + parseInt(hourStr, 10), + parseInt(minuteStr, 10), + ]; + + if (secondStr) { + result.push(parseInt(secondStr, 10)); + } + + return result; + } + + function untruncateYear(yearStr) { + var year = parseInt(yearStr, 10); + if (year <= 49) { + return 2000 + year; + } else if (year <= 999) { + return 1900 + year; + } + return year; + } + + function preprocessRFC2822(s) { + // Remove comments and folding whitespace and replace multiple-spaces with a single space + return s + .replace(/\([^()]*\)|[\n\t]/g, ' ') + .replace(/(\s\s+)/g, ' ') + .replace(/^\s\s*/, '') + .replace(/\s\s*$/, ''); + } + + function checkWeekday(weekdayStr, parsedInput, config) { + if (weekdayStr) { + // TODO: Replace the vanilla JS Date object with an independent day-of-week check. + var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), + weekdayActual = new Date( + parsedInput[0], + parsedInput[1], + parsedInput[2] + ).getDay(); + if (weekdayProvided !== weekdayActual) { + getParsingFlags(config).weekdayMismatch = true; + config._isValid = false; + return false; + } + } + return true; + } + + function calculateOffset(obsOffset, militaryOffset, numOffset) { + if (obsOffset) { + return obsOffsets[obsOffset]; + } else if (militaryOffset) { + // the only allowed military tz is Z + return 0; + } else { + var hm = parseInt(numOffset, 10), + m = hm % 100, + h = (hm - m) / 100; + return h * 60 + m; + } + } + + // date and time from ref 2822 format + function configFromRFC2822(config) { + var match = rfc2822.exec(preprocessRFC2822(config._i)), + parsedArray; + if (match) { + parsedArray = extractFromRFC2822Strings( + match[4], + match[3], + match[2], + match[5], + match[6], + match[7] + ); + if (!checkWeekday(match[1], parsedArray, config)) { + return; + } + + config._a = parsedArray; + config._tzm = calculateOffset(match[8], match[9], match[10]); + + config._d = createUTCDate.apply(null, config._a); + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + + getParsingFlags(config).rfc2822 = true; + } else { + config._isValid = false; + } + } + + // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict + function configFromString(config) { + var matched = aspNetJsonRegex.exec(config._i); + if (matched !== null) { + config._d = new Date(+matched[1]); + return; + } + + configFromISO(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + configFromRFC2822(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + if (config._strict) { + config._isValid = false; + } else { + // Final attempt, use Input Fallback + hooks.createFromInputFallback(config); + } + } + + hooks.createFromInputFallback = deprecate( + 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + + 'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + // Pick the first defined of two or three arguments. + function defaults(a, b, c) { + if (a != null) { + return a; + } + if (b != null) { + return b; + } + return c; + } + + function currentDateArray(config) { + // hooks is actually the exported moment object + var nowValue = new Date(hooks.now()); + if (config._useUTC) { + return [ + nowValue.getUTCFullYear(), + nowValue.getUTCMonth(), + nowValue.getUTCDate(), + ]; + } + return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function configFromArray(config) { + var i, + date, + input = [], + currentDate, + expectedWeekday, + yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear != null) { + yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); + + if ( + config._dayOfYear > daysInYear(yearToUse) || + config._dayOfYear === 0 + ) { + getParsingFlags(config)._overflowDayOfYear = true; + } + + date = createUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = + config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if ( + config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0 + ) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? createUTCDate : createDate).apply( + null, + input + ); + expectedWeekday = config._useUTC + ? config._d.getUTCDay() + : config._d.getDay(); + + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + + // check for mismatching day of week + if ( + config._w && + typeof config._w.d !== 'undefined' && + config._w.d !== expectedWeekday + ) { + getParsingFlags(config).weekdayMismatch = true; + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = defaults( + w.GG, + config._a[YEAR], + weekOfYear(createLocal(), 1, 4).year + ); + week = defaults(w.W, 1); + weekday = defaults(w.E, 1); + if (weekday < 1 || weekday > 7) { + weekdayOverflow = true; + } + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + curWeek = weekOfYear(createLocal(), dow, doy); + + weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); + + // Default to current week. + week = defaults(w.w, curWeek.week); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < 0 || weekday > 6) { + weekdayOverflow = true; + } + } else if (w.e != null) { + // local weekday -- counting starts from beginning of week + weekday = w.e + dow; + if (w.e < 0 || w.e > 6) { + weekdayOverflow = true; + } + } else { + // default to beginning of week + weekday = dow; + } + } + if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { + getParsingFlags(config)._overflowWeeks = true; + } else if (weekdayOverflow != null) { + getParsingFlags(config)._overflowWeekday = true; + } else { + temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + } + + // constant that refers to the ISO standard + hooks.ISO_8601 = function () {}; + + // constant that refers to the RFC 2822 form + hooks.RFC_2822 = function () {}; + + // date from string and format string + function configFromStringAndFormat(config) { + // TODO: Move this to another part of the creation flow to prevent circular deps + if (config._f === hooks.ISO_8601) { + configFromISO(config); + return; + } + if (config._f === hooks.RFC_2822) { + configFromRFC2822(config); + return; + } + config._a = []; + getParsingFlags(config).empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, + parsedInput, + tokens, + token, + skipped, + stringLength = string.length, + totalParsedInputLength = 0, + era, + tokenLen; + + tokens = + expandFormat(config._f, config._locale).match(formattingTokens) || []; + tokenLen = tokens.length; + for (i = 0; i < tokenLen; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || + [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + getParsingFlags(config).unusedInput.push(skipped); + } + string = string.slice( + string.indexOf(parsedInput) + parsedInput.length + ); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + getParsingFlags(config).empty = false; + } else { + getParsingFlags(config).unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } else if (config._strict && !parsedInput) { + getParsingFlags(config).unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + getParsingFlags(config).charsLeftOver = + stringLength - totalParsedInputLength; + if (string.length > 0) { + getParsingFlags(config).unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if ( + config._a[HOUR] <= 12 && + getParsingFlags(config).bigHour === true && + config._a[HOUR] > 0 + ) { + getParsingFlags(config).bigHour = undefined; + } + + getParsingFlags(config).parsedDateParts = config._a.slice(0); + getParsingFlags(config).meridiem = config._meridiem; + // handle meridiem + config._a[HOUR] = meridiemFixWrap( + config._locale, + config._a[HOUR], + config._meridiem + ); + + // handle era + era = getParsingFlags(config).era; + if (era !== null) { + config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]); + } + + configFromArray(config); + checkOverflow(config); + } + + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // this is not supposed to happen + return hour; + } + } + + // date from string and array of format strings + function configFromStringAndArray(config) { + var tempConfig, + bestMoment, + scoreToBeat, + i, + currentScore, + validFormatFound, + bestFormatIsValid = false, + configfLen = config._f.length; + + if (configfLen === 0) { + getParsingFlags(config).invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < configfLen; i++) { + currentScore = 0; + validFormatFound = false; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._f = config._f[i]; + configFromStringAndFormat(tempConfig); + + if (isValid(tempConfig)) { + validFormatFound = true; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += getParsingFlags(tempConfig).charsLeftOver; + + //or tokens + currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; + + getParsingFlags(tempConfig).score = currentScore; + + if (!bestFormatIsValid) { + if ( + scoreToBeat == null || + currentScore < scoreToBeat || + validFormatFound + ) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + if (validFormatFound) { + bestFormatIsValid = true; + } + } + } else { + if (currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + } + + extend(config, bestMoment || tempConfig); + } + + function configFromObject(config) { + if (config._d) { + return; + } + + var i = normalizeObjectUnits(config._i), + dayOrDate = i.day === undefined ? i.date : i.day; + config._a = map( + [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond], + function (obj) { + return obj && parseInt(obj, 10); + } + ); + + configFromArray(config); + } + + function createFromConfig(config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + function prepareConfig(config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || getLocale(config._l); + + if (input === null || (format === undefined && input === '')) { + return createInvalid({ nullInput: true }); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (isMoment(input)) { + return new Moment(checkOverflow(input)); + } else if (isDate(input)) { + config._d = input; + } else if (isArray(format)) { + configFromStringAndArray(config); + } else if (format) { + configFromStringAndFormat(config); + } else { + configFromInput(config); + } + + if (!isValid(config)) { + config._d = null; + } + + return config; + } + + function configFromInput(config) { + var input = config._i; + if (isUndefined(input)) { + config._d = new Date(hooks.now()); + } else if (isDate(input)) { + config._d = new Date(input.valueOf()); + } else if (typeof input === 'string') { + configFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + configFromArray(config); + } else if (isObject(input)) { + configFromObject(config); + } else if (isNumber(input)) { + // from milliseconds + config._d = new Date(input); + } else { + hooks.createFromInputFallback(config); + } + } + + function createLocalOrUTC(input, format, locale, strict, isUTC) { + var c = {}; + + if (format === true || format === false) { + strict = format; + format = undefined; + } + + if (locale === true || locale === false) { + strict = locale; + locale = undefined; + } + + if ( + (isObject(input) && isObjectEmpty(input)) || + (isArray(input) && input.length === 0) + ) { + input = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c._isAMomentObject = true; + c._useUTC = c._isUTC = isUTC; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + + return createFromConfig(c); + } + + function createLocal(input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, false); + } + + var prototypeMin = deprecate( + 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other < this ? this : other; + } else { + return createInvalid(); + } + } + ), + prototypeMax = deprecate( + 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other > this ? this : other; + } else { + return createInvalid(); + } + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return createLocal(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (!moments[i].isValid() || moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + // TODO: Use [].sort instead? + function min() { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + } + + function max() { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + } + + var now = function () { + return Date.now ? Date.now() : +new Date(); + }; + + var ordering = [ + 'year', + 'quarter', + 'month', + 'week', + 'day', + 'hour', + 'minute', + 'second', + 'millisecond', + ]; + + function isDurationValid(m) { + var key, + unitHasDecimal = false, + i, + orderLen = ordering.length; + for (key in m) { + if ( + hasOwnProp(m, key) && + !( + indexOf.call(ordering, key) !== -1 && + (m[key] == null || !isNaN(m[key])) + ) + ) { + return false; + } + } + + for (i = 0; i < orderLen; ++i) { + if (m[ordering[i]]) { + if (unitHasDecimal) { + return false; // only allow non-integers for smallest unit + } + if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { + unitHasDecimal = true; + } + } + } + + return true; + } + + function isValid$1() { + return this._isValid; + } + + function createInvalid$1() { + return createDuration(NaN); + } + + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || normalizedInput.isoWeek || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + this._isValid = isDurationValid(normalizedInput); + + // representation for dateAddRemove + this._milliseconds = + +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + weeks * 7; + // It is impossible to translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + quarters * 3 + years * 12; + + this._data = {}; + + this._locale = getLocale(); + + this._bubble(); + } + + function isDuration(obj) { + return obj instanceof Duration; + } + + function absRound(number) { + if (number < 0) { + return Math.round(-1 * number) * -1; + } else { + return Math.round(number); + } + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ( + (dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i])) + ) { + diffs++; + } + } + return diffs + lengthDiff; + } + + // FORMATTING + + function offset(token, separator) { + addFormatToken(token, 0, 0, function () { + var offset = this.utcOffset(), + sign = '+'; + if (offset < 0) { + offset = -offset; + sign = '-'; + } + return ( + sign + + zeroFill(~~(offset / 60), 2) + + separator + + zeroFill(~~offset % 60, 2) + ); + }); + } + + offset('Z', ':'); + offset('ZZ', ''); + + // PARSING + + addRegexToken('Z', matchShortOffset); + addRegexToken('ZZ', matchShortOffset); + addParseToken(['Z', 'ZZ'], function (input, array, config) { + config._useUTC = true; + config._tzm = offsetFromString(matchShortOffset, input); + }); + + // HELPERS + + // timezone chunker + // '+10:00' > ['10', '00'] + // '-1530' > ['-15', '30'] + var chunkOffset = /([\+\-]|\d\d)/gi; + + function offsetFromString(matcher, string) { + var matches = (string || '').match(matcher), + chunk, + parts, + minutes; + + if (matches === null) { + return null; + } + + chunk = matches[matches.length - 1] || []; + parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function cloneWithOffset(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = + (isMoment(input) || isDate(input) + ? input.valueOf() + : createLocal(input).valueOf()) - res.valueOf(); + // Use low-level api, because this fn is low-level api. + res._d.setTime(res._d.valueOf() + diff); + hooks.updateOffset(res, false); + return res; + } else { + return createLocal(input).local(); + } + } + + function getDateOffset(m) { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(m._d.getTimezoneOffset()); + } + + // HOOKS + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + hooks.updateOffset = function () {}; + + // MOMENTS + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + function getSetOffset(input, keepLocalTime, keepMinutes) { + var offset = this._offset || 0, + localAdjust; + if (!this.isValid()) { + return input != null ? this : NaN; + } + if (input != null) { + if (typeof input === 'string') { + input = offsetFromString(matchShortOffset, input); + if (input === null) { + return this; + } + } else if (Math.abs(input) < 16 && !keepMinutes) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = getDateOffset(this); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addSubtract( + this, + createDuration(input - offset, 'm'), + 1, + false + ); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + hooks.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : getDateOffset(this); + } + } + + function getSetZone(input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + + function setOffsetToUTC(keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + } + + function setOffsetToLocal(keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(getDateOffset(this), 'm'); + } + } + return this; + } + + function setOffsetToParsedOffset() { + if (this._tzm != null) { + this.utcOffset(this._tzm, false, true); + } else if (typeof this._i === 'string') { + var tZone = offsetFromString(matchOffset, this._i); + if (tZone != null) { + this.utcOffset(tZone); + } else { + this.utcOffset(0, true); + } + } + return this; + } + + function hasAlignedHourOffset(input) { + if (!this.isValid()) { + return false; + } + input = input ? createLocal(input).utcOffset() : 0; + + return (this.utcOffset() - input) % 60 === 0; + } + + function isDaylightSavingTime() { + return ( + this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset() + ); + } + + function isDaylightSavingTimeShifted() { + if (!isUndefined(this._isDSTShifted)) { + return this._isDSTShifted; + } + + var c = {}, + other; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + other = c._isUTC ? createUTC(c._a) : createLocal(c._a); + this._isDSTShifted = + this.isValid() && compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; + } + + function isLocal() { + return this.isValid() ? !this._isUTC : false; + } + + function isUtcOffset() { + return this.isValid() ? this._isUTC : false; + } + + function isUtc() { + return this.isValid() ? this._isUTC && this._offset === 0 : false; + } + + // ASP.NET json date format regex + var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + // and further modified to allow for strings containing both week and day + isoRegex = + /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; + + function createDuration(input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + diffRes; + + if (isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months, + }; + } else if (isNumber(input) || !isNaN(+input)) { + duration = {}; + if (key) { + duration[key] = +input; + } else { + duration.milliseconds = +input; + } + } else if ((match = aspNetRegex.exec(input))) { + sign = match[1] === '-' ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match + }; + } else if ((match = isoRegex.exec(input))) { + sign = match[1] === '-' ? -1 : 1; + duration = { + y: parseIso(match[2], sign), + M: parseIso(match[3], sign), + w: parseIso(match[4], sign), + d: parseIso(match[5], sign), + h: parseIso(match[6], sign), + m: parseIso(match[7], sign), + s: parseIso(match[8], sign), + }; + } else if (duration == null) { + // checks for null or undefined + duration = {}; + } else if ( + typeof duration === 'object' && + ('from' in duration || 'to' in duration) + ) { + diffRes = momentsDifference( + createLocal(duration.from), + createLocal(duration.to) + ); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + if (isDuration(input) && hasOwnProp(input, '_isValid')) { + ret._isValid = input._isValid; + } + + return ret; + } + + createDuration.fn = Duration.prototype; + createDuration.invalid = createInvalid$1; + + function parseIso(inp, sign) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + } + + function positiveMomentsDifference(base, other) { + var res = {}; + + res.months = + other.month() - base.month() + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +base.clone().add(res.months, 'M'); + + return res; + } + + function momentsDifference(base, other) { + var res; + if (!(base.isValid() && other.isValid())) { + return { milliseconds: 0, months: 0 }; + } + + other = cloneWithOffset(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple( + name, + 'moment().' + + name + + '(period, number) is deprecated. Please use moment().' + + name + + '(number, period). ' + + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.' + ); + tmp = val; + val = period; + period = tmp; + } + + dur = createDuration(val, period); + addSubtract(this, dur, direction); + return this; + }; + } + + function addSubtract(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = absRound(duration._days), + months = absRound(duration._months); + + if (!mom.isValid()) { + // No op + return; + } + + updateOffset = updateOffset == null ? true : updateOffset; + + if (months) { + setMonth(mom, get(mom, 'Month') + months * isAdding); + } + if (days) { + set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); + } + if (milliseconds) { + mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); + } + if (updateOffset) { + hooks.updateOffset(mom, days || months); + } + } + + var add = createAdder(1, 'add'), + subtract = createAdder(-1, 'subtract'); + + function isString(input) { + return typeof input === 'string' || input instanceof String; + } + + // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined + function isMomentInput(input) { + return ( + isMoment(input) || + isDate(input) || + isString(input) || + isNumber(input) || + isNumberOrStringArray(input) || + isMomentInputObject(input) || + input === null || + input === undefined + ); + } + + function isMomentInputObject(input) { + var objectTest = isObject(input) && !isObjectEmpty(input), + propertyTest = false, + properties = [ + 'years', + 'year', + 'y', + 'months', + 'month', + 'M', + 'days', + 'day', + 'd', + 'dates', + 'date', + 'D', + 'hours', + 'hour', + 'h', + 'minutes', + 'minute', + 'm', + 'seconds', + 'second', + 's', + 'milliseconds', + 'millisecond', + 'ms', + ], + i, + property, + propertyLen = properties.length; + + for (i = 0; i < propertyLen; i += 1) { + property = properties[i]; + propertyTest = propertyTest || hasOwnProp(input, property); + } + + return objectTest && propertyTest; + } + + function isNumberOrStringArray(input) { + var arrayTest = isArray(input), + dataTypeTest = false; + if (arrayTest) { + dataTypeTest = + input.filter(function (item) { + return !isNumber(item) && isString(input); + }).length === 0; + } + return arrayTest && dataTypeTest; + } + + function isCalendarSpec(input) { + var objectTest = isObject(input) && !isObjectEmpty(input), + propertyTest = false, + properties = [ + 'sameDay', + 'nextDay', + 'lastDay', + 'nextWeek', + 'lastWeek', + 'sameElse', + ], + i, + property; + + for (i = 0; i < properties.length; i += 1) { + property = properties[i]; + propertyTest = propertyTest || hasOwnProp(input, property); + } + + return objectTest && propertyTest; + } + + function getCalendarFormat(myMoment, now) { + var diff = myMoment.diff(now, 'days', true); + return diff < -6 + ? 'sameElse' + : diff < -1 + ? 'lastWeek' + : diff < 0 + ? 'lastDay' + : diff < 1 + ? 'sameDay' + : diff < 2 + ? 'nextDay' + : diff < 7 + ? 'nextWeek' + : 'sameElse'; + } + + function calendar$1(time, formats) { + // Support for single parameter, formats only overload to the calendar function + if (arguments.length === 1) { + if (!arguments[0]) { + time = undefined; + formats = undefined; + } else if (isMomentInput(arguments[0])) { + time = arguments[0]; + formats = undefined; + } else if (isCalendarSpec(arguments[0])) { + formats = arguments[0]; + time = undefined; + } + } + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're local/utc/offset or not. + var now = time || createLocal(), + sod = cloneWithOffset(now, this).startOf('day'), + format = hooks.calendarFormat(this, sod) || 'sameElse', + output = + formats && + (isFunction(formats[format]) + ? formats[format].call(this, now) + : formats[format]); + + return this.format( + output || this.localeData().calendar(format, this, createLocal(now)) + ); + } + + function clone() { + return new Moment(this); + } + + function isAfter(input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() > localInput.valueOf(); + } else { + return localInput.valueOf() < this.clone().startOf(units).valueOf(); + } + } + + function isBefore(input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() < localInput.valueOf(); + } else { + return this.clone().endOf(units).valueOf() < localInput.valueOf(); + } + } + + function isBetween(from, to, units, inclusivity) { + var localFrom = isMoment(from) ? from : createLocal(from), + localTo = isMoment(to) ? to : createLocal(to); + if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) { + return false; + } + inclusivity = inclusivity || '()'; + return ( + (inclusivity[0] === '(' + ? this.isAfter(localFrom, units) + : !this.isBefore(localFrom, units)) && + (inclusivity[1] === ')' + ? this.isBefore(localTo, units) + : !this.isAfter(localTo, units)) + ); + } + + function isSame(input, units) { + var localInput = isMoment(input) ? input : createLocal(input), + inputMs; + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() === localInput.valueOf(); + } else { + inputMs = localInput.valueOf(); + return ( + this.clone().startOf(units).valueOf() <= inputMs && + inputMs <= this.clone().endOf(units).valueOf() + ); + } + } + + function isSameOrAfter(input, units) { + return this.isSame(input, units) || this.isAfter(input, units); + } + + function isSameOrBefore(input, units) { + return this.isSame(input, units) || this.isBefore(input, units); + } + + function diff(input, units, asFloat) { + var that, zoneDelta, output; + + if (!this.isValid()) { + return NaN; + } + + that = cloneWithOffset(input, this); + + if (!that.isValid()) { + return NaN; + } + + zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; + + units = normalizeUnits(units); + + switch (units) { + case 'year': + output = monthDiff(this, that) / 12; + break; + case 'month': + output = monthDiff(this, that); + break; + case 'quarter': + output = monthDiff(this, that) / 3; + break; + case 'second': + output = (this - that) / 1e3; + break; // 1000 + case 'minute': + output = (this - that) / 6e4; + break; // 1000 * 60 + case 'hour': + output = (this - that) / 36e5; + break; // 1000 * 60 * 60 + case 'day': + output = (this - that - zoneDelta) / 864e5; + break; // 1000 * 60 * 60 * 24, negate dst + case 'week': + output = (this - that - zoneDelta) / 6048e5; + break; // 1000 * 60 * 60 * 24 * 7, negate dst + default: + output = this - that; + } + + return asFloat ? output : absFloor(output); + } + + function monthDiff(a, b) { + if (a.date() < b.date()) { + // end-of-month calculations work correct when the start month has more + // days than the end month. + return -monthDiff(b, a); + } + // difference in months + var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, + adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + //check for negative zero, return zero if negative zero + return -(wholeMonthDiff + adjust) || 0; + } + + hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; + hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; + + function toString() { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + } + + function toISOString(keepOffset) { + if (!this.isValid()) { + return null; + } + var utc = keepOffset !== true, + m = utc ? this.clone().utc() : this; + if (m.year() < 0 || m.year() > 9999) { + return formatMoment( + m, + utc + ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' + : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ' + ); + } + if (isFunction(Date.prototype.toISOString)) { + // native implementation is ~50x faster, use it when we can + if (utc) { + return this.toDate().toISOString(); + } else { + return new Date(this.valueOf() + this.utcOffset() * 60 * 1000) + .toISOString() + .replace('Z', formatMoment(m, 'Z')); + } + } + return formatMoment( + m, + utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ' + ); + } + + /** + * Return a human readable representation of a moment that can + * also be evaluated to get a new moment which is the same + * + * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects + */ + function inspect() { + if (!this.isValid()) { + return 'moment.invalid(/* ' + this._i + ' */)'; + } + var func = 'moment', + zone = '', + prefix, + year, + datetime, + suffix; + if (!this.isLocal()) { + func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; + zone = 'Z'; + } + prefix = '[' + func + '("]'; + year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY'; + datetime = '-MM-DD[T]HH:mm:ss.SSS'; + suffix = zone + '[")]'; + + return this.format(prefix + year + datetime + suffix); + } + + function format(inputString) { + if (!inputString) { + inputString = this.isUtc() + ? hooks.defaultFormatUtc + : hooks.defaultFormat; + } + var output = formatMoment(this, inputString); + return this.localeData().postformat(output); + } + + function from(time, withoutSuffix) { + if ( + this.isValid() && + ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) + ) { + return createDuration({ to: this, from: time }) + .locale(this.locale()) + .humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function fromNow(withoutSuffix) { + return this.from(createLocal(), withoutSuffix); + } + + function to(time, withoutSuffix) { + if ( + this.isValid() && + ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) + ) { + return createDuration({ from: this, to: time }) + .locale(this.locale()) + .humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function toNow(withoutSuffix) { + return this.to(createLocal(), withoutSuffix); + } + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + function locale(key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = getLocale(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + } + + var lang = deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ); + + function localeData() { + return this._locale; + } + + var MS_PER_SECOND = 1000, + MS_PER_MINUTE = 60 * MS_PER_SECOND, + MS_PER_HOUR = 60 * MS_PER_MINUTE, + MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; + + // actual modulo - handles negative numbers (for dates before 1970): + function mod$1(dividend, divisor) { + return ((dividend % divisor) + divisor) % divisor; + } + + function localStartOfDate(y, m, d) { + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + return new Date(y + 400, m, d) - MS_PER_400_YEARS; + } else { + return new Date(y, m, d).valueOf(); + } + } + + function utcStartOfDate(y, m, d) { + // Date.UTC remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS; + } else { + return Date.UTC(y, m, d); + } + } + + function startOf(units) { + var time, startOfDate; + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond' || !this.isValid()) { + return this; + } + + startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; + + switch (units) { + case 'year': + time = startOfDate(this.year(), 0, 1); + break; + case 'quarter': + time = startOfDate( + this.year(), + this.month() - (this.month() % 3), + 1 + ); + break; + case 'month': + time = startOfDate(this.year(), this.month(), 1); + break; + case 'week': + time = startOfDate( + this.year(), + this.month(), + this.date() - this.weekday() + ); + break; + case 'isoWeek': + time = startOfDate( + this.year(), + this.month(), + this.date() - (this.isoWeekday() - 1) + ); + break; + case 'day': + case 'date': + time = startOfDate(this.year(), this.month(), this.date()); + break; + case 'hour': + time = this._d.valueOf(); + time -= mod$1( + time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), + MS_PER_HOUR + ); + break; + case 'minute': + time = this._d.valueOf(); + time -= mod$1(time, MS_PER_MINUTE); + break; + case 'second': + time = this._d.valueOf(); + time -= mod$1(time, MS_PER_SECOND); + break; + } + + this._d.setTime(time); + hooks.updateOffset(this, true); + return this; + } + + function endOf(units) { + var time, startOfDate; + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond' || !this.isValid()) { + return this; + } + + startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; + + switch (units) { + case 'year': + time = startOfDate(this.year() + 1, 0, 1) - 1; + break; + case 'quarter': + time = + startOfDate( + this.year(), + this.month() - (this.month() % 3) + 3, + 1 + ) - 1; + break; + case 'month': + time = startOfDate(this.year(), this.month() + 1, 1) - 1; + break; + case 'week': + time = + startOfDate( + this.year(), + this.month(), + this.date() - this.weekday() + 7 + ) - 1; + break; + case 'isoWeek': + time = + startOfDate( + this.year(), + this.month(), + this.date() - (this.isoWeekday() - 1) + 7 + ) - 1; + break; + case 'day': + case 'date': + time = startOfDate(this.year(), this.month(), this.date() + 1) - 1; + break; + case 'hour': + time = this._d.valueOf(); + time += + MS_PER_HOUR - + mod$1( + time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), + MS_PER_HOUR + ) - + 1; + break; + case 'minute': + time = this._d.valueOf(); + time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1; + break; + case 'second': + time = this._d.valueOf(); + time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1; + break; + } + + this._d.setTime(time); + hooks.updateOffset(this, true); + return this; + } + + function valueOf() { + return this._d.valueOf() - (this._offset || 0) * 60000; + } + + function unix() { + return Math.floor(this.valueOf() / 1000); + } + + function toDate() { + return new Date(this.valueOf()); + } + + function toArray() { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hour(), + m.minute(), + m.second(), + m.millisecond(), + ]; + } + + function toObject() { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds(), + }; + } + + function toJSON() { + // new Date(NaN).toJSON() === null + return this.isValid() ? this.toISOString() : null; + } + + function isValid$2() { + return isValid(this); + } + + function parsingFlags() { + return extend({}, getParsingFlags(this)); + } + + function invalidAt() { + return getParsingFlags(this).overflow; + } + + function creationData() { + return { + input: this._i, + format: this._f, + locale: this._locale, + isUTC: this._isUTC, + strict: this._strict, + }; + } + + addFormatToken('N', 0, 0, 'eraAbbr'); + addFormatToken('NN', 0, 0, 'eraAbbr'); + addFormatToken('NNN', 0, 0, 'eraAbbr'); + addFormatToken('NNNN', 0, 0, 'eraName'); + addFormatToken('NNNNN', 0, 0, 'eraNarrow'); + + addFormatToken('y', ['y', 1], 'yo', 'eraYear'); + addFormatToken('y', ['yy', 2], 0, 'eraYear'); + addFormatToken('y', ['yyy', 3], 0, 'eraYear'); + addFormatToken('y', ['yyyy', 4], 0, 'eraYear'); + + addRegexToken('N', matchEraAbbr); + addRegexToken('NN', matchEraAbbr); + addRegexToken('NNN', matchEraAbbr); + addRegexToken('NNNN', matchEraName); + addRegexToken('NNNNN', matchEraNarrow); + + addParseToken( + ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], + function (input, array, config, token) { + var era = config._locale.erasParse(input, token, config._strict); + if (era) { + getParsingFlags(config).era = era; + } else { + getParsingFlags(config).invalidEra = input; + } + } + ); + + addRegexToken('y', matchUnsigned); + addRegexToken('yy', matchUnsigned); + addRegexToken('yyy', matchUnsigned); + addRegexToken('yyyy', matchUnsigned); + addRegexToken('yo', matchEraYearOrdinal); + + addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR); + addParseToken(['yo'], function (input, array, config, token) { + var match; + if (config._locale._eraYearOrdinalRegex) { + match = input.match(config._locale._eraYearOrdinalRegex); + } + + if (config._locale.eraYearOrdinalParse) { + array[YEAR] = config._locale.eraYearOrdinalParse(input, match); + } else { + array[YEAR] = parseInt(input, 10); + } + }); + + function localeEras(m, format) { + var i, + l, + date, + eras = this._eras || getLocale('en')._eras; + for (i = 0, l = eras.length; i < l; ++i) { + switch (typeof eras[i].since) { + case 'string': + // truncate time + date = hooks(eras[i].since).startOf('day'); + eras[i].since = date.valueOf(); + break; + } + + switch (typeof eras[i].until) { + case 'undefined': + eras[i].until = +Infinity; + break; + case 'string': + // truncate time + date = hooks(eras[i].until).startOf('day').valueOf(); + eras[i].until = date.valueOf(); + break; + } + } + return eras; + } + + function localeErasParse(eraName, format, strict) { + var i, + l, + eras = this.eras(), + name, + abbr, + narrow; + eraName = eraName.toUpperCase(); + + for (i = 0, l = eras.length; i < l; ++i) { + name = eras[i].name.toUpperCase(); + abbr = eras[i].abbr.toUpperCase(); + narrow = eras[i].narrow.toUpperCase(); + + if (strict) { + switch (format) { + case 'N': + case 'NN': + case 'NNN': + if (abbr === eraName) { + return eras[i]; + } + break; + + case 'NNNN': + if (name === eraName) { + return eras[i]; + } + break; + + case 'NNNNN': + if (narrow === eraName) { + return eras[i]; + } + break; + } + } else if ([name, abbr, narrow].indexOf(eraName) >= 0) { + return eras[i]; + } + } + } + + function localeErasConvertYear(era, year) { + var dir = era.since <= era.until ? +1 : -1; + if (year === undefined) { + return hooks(era.since).year(); + } else { + return hooks(era.since).year() + (year - era.offset) * dir; + } + } + + function getEraName() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].name; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].name; + } + } + + return ''; + } + + function getEraNarrow() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].narrow; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].narrow; + } + } + + return ''; + } + + function getEraAbbr() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].abbr; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].abbr; + } + } + + return ''; + } + + function getEraYear() { + var i, + l, + dir, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + dir = eras[i].since <= eras[i].until ? +1 : -1; + + // truncate time + val = this.clone().startOf('day').valueOf(); + + if ( + (eras[i].since <= val && val <= eras[i].until) || + (eras[i].until <= val && val <= eras[i].since) + ) { + return ( + (this.year() - hooks(eras[i].since).year()) * dir + + eras[i].offset + ); + } + } + + return this.year(); + } + + function erasNameRegex(isStrict) { + if (!hasOwnProp(this, '_erasNameRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasNameRegex : this._erasRegex; + } + + function erasAbbrRegex(isStrict) { + if (!hasOwnProp(this, '_erasAbbrRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasAbbrRegex : this._erasRegex; + } + + function erasNarrowRegex(isStrict) { + if (!hasOwnProp(this, '_erasNarrowRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasNarrowRegex : this._erasRegex; + } + + function matchEraAbbr(isStrict, locale) { + return locale.erasAbbrRegex(isStrict); + } + + function matchEraName(isStrict, locale) { + return locale.erasNameRegex(isStrict); + } + + function matchEraNarrow(isStrict, locale) { + return locale.erasNarrowRegex(isStrict); + } + + function matchEraYearOrdinal(isStrict, locale) { + return locale._eraYearOrdinalRegex || matchUnsigned; + } + + function computeErasParse() { + var abbrPieces = [], + namePieces = [], + narrowPieces = [], + mixedPieces = [], + i, + l, + eras = this.eras(); + + for (i = 0, l = eras.length; i < l; ++i) { + namePieces.push(regexEscape(eras[i].name)); + abbrPieces.push(regexEscape(eras[i].abbr)); + narrowPieces.push(regexEscape(eras[i].narrow)); + + mixedPieces.push(regexEscape(eras[i].name)); + mixedPieces.push(regexEscape(eras[i].abbr)); + mixedPieces.push(regexEscape(eras[i].narrow)); + } + + this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i'); + this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i'); + this._erasNarrowRegex = new RegExp( + '^(' + narrowPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + addFormatToken(0, ['gg', 2], 0, function () { + return this.weekYear() % 100; + }); + + addFormatToken(0, ['GG', 2], 0, function () { + return this.isoWeekYear() % 100; + }); + + function addWeekYearFormatToken(token, getter) { + addFormatToken(0, [token, token.length], 0, getter); + } + + addWeekYearFormatToken('gggg', 'weekYear'); + addWeekYearFormatToken('ggggg', 'weekYear'); + addWeekYearFormatToken('GGGG', 'isoWeekYear'); + addWeekYearFormatToken('GGGGG', 'isoWeekYear'); + + // ALIASES + + addUnitAlias('weekYear', 'gg'); + addUnitAlias('isoWeekYear', 'GG'); + + // PRIORITY + + addUnitPriority('weekYear', 1); + addUnitPriority('isoWeekYear', 1); + + // PARSING + + addRegexToken('G', matchSigned); + addRegexToken('g', matchSigned); + addRegexToken('GG', match1to2, match2); + addRegexToken('gg', match1to2, match2); + addRegexToken('GGGG', match1to4, match4); + addRegexToken('gggg', match1to4, match4); + addRegexToken('GGGGG', match1to6, match6); + addRegexToken('ggggg', match1to6, match6); + + addWeekParseToken( + ['gggg', 'ggggg', 'GGGG', 'GGGGG'], + function (input, week, config, token) { + week[token.substr(0, 2)] = toInt(input); + } + ); + + addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { + week[token] = hooks.parseTwoDigitYear(input); + }); + + // MOMENTS + + function getSetWeekYear(input) { + return getSetWeekYearHelper.call( + this, + input, + this.week(), + this.weekday(), + this.localeData()._week.dow, + this.localeData()._week.doy + ); + } + + function getSetISOWeekYear(input) { + return getSetWeekYearHelper.call( + this, + input, + this.isoWeek(), + this.isoWeekday(), + 1, + 4 + ); + } + + function getISOWeeksInYear() { + return weeksInYear(this.year(), 1, 4); + } + + function getISOWeeksInISOWeekYear() { + return weeksInYear(this.isoWeekYear(), 1, 4); + } + + function getWeeksInYear() { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + } + + function getWeeksInWeekYear() { + var weekInfo = this.localeData()._week; + return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy); + } + + function getSetWeekYearHelper(input, week, weekday, dow, doy) { + var weeksTarget; + if (input == null) { + return weekOfYear(this, dow, doy).year; + } else { + weeksTarget = weeksInYear(input, dow, doy); + if (week > weeksTarget) { + week = weeksTarget; + } + return setWeekAll.call(this, input, week, weekday, dow, doy); + } + } + + function setWeekAll(weekYear, week, weekday, dow, doy) { + var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), + date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); + + this.year(date.getUTCFullYear()); + this.month(date.getUTCMonth()); + this.date(date.getUTCDate()); + return this; + } + + // FORMATTING + + addFormatToken('Q', 0, 'Qo', 'quarter'); + + // ALIASES + + addUnitAlias('quarter', 'Q'); + + // PRIORITY + + addUnitPriority('quarter', 7); + + // PARSING + + addRegexToken('Q', match1); + addParseToken('Q', function (input, array) { + array[MONTH] = (toInt(input) - 1) * 3; + }); + + // MOMENTS + + function getSetQuarter(input) { + return input == null + ? Math.ceil((this.month() + 1) / 3) + : this.month((input - 1) * 3 + (this.month() % 3)); + } + + // FORMATTING + + addFormatToken('D', ['DD', 2], 'Do', 'date'); + + // ALIASES + + addUnitAlias('date', 'D'); + + // PRIORITY + addUnitPriority('date', 9); + + // PARSING + + addRegexToken('D', match1to2); + addRegexToken('DD', match1to2, match2); + addRegexToken('Do', function (isStrict, locale) { + // TODO: Remove "ordinalParse" fallback in next major release. + return isStrict + ? locale._dayOfMonthOrdinalParse || locale._ordinalParse + : locale._dayOfMonthOrdinalParseLenient; + }); + + addParseToken(['D', 'DD'], DATE); + addParseToken('Do', function (input, array) { + array[DATE] = toInt(input.match(match1to2)[0]); + }); + + // MOMENTS + + var getSetDayOfMonth = makeGetSet('Date', true); + + // FORMATTING + + addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); + + // ALIASES + + addUnitAlias('dayOfYear', 'DDD'); + + // PRIORITY + addUnitPriority('dayOfYear', 4); + + // PARSING + + addRegexToken('DDD', match1to3); + addRegexToken('DDDD', match3); + addParseToken(['DDD', 'DDDD'], function (input, array, config) { + config._dayOfYear = toInt(input); + }); + + // HELPERS + + // MOMENTS + + function getSetDayOfYear(input) { + var dayOfYear = + Math.round( + (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5 + ) + 1; + return input == null ? dayOfYear : this.add(input - dayOfYear, 'd'); + } + + // FORMATTING + + addFormatToken('m', ['mm', 2], 0, 'minute'); + + // ALIASES + + addUnitAlias('minute', 'm'); + + // PRIORITY + + addUnitPriority('minute', 14); + + // PARSING + + addRegexToken('m', match1to2); + addRegexToken('mm', match1to2, match2); + addParseToken(['m', 'mm'], MINUTE); + + // MOMENTS + + var getSetMinute = makeGetSet('Minutes', false); + + // FORMATTING + + addFormatToken('s', ['ss', 2], 0, 'second'); + + // ALIASES + + addUnitAlias('second', 's'); + + // PRIORITY + + addUnitPriority('second', 15); + + // PARSING + + addRegexToken('s', match1to2); + addRegexToken('ss', match1to2, match2); + addParseToken(['s', 'ss'], SECOND); + + // MOMENTS + + var getSetSecond = makeGetSet('Seconds', false); + + // FORMATTING + + addFormatToken('S', 0, 0, function () { + return ~~(this.millisecond() / 100); + }); + + addFormatToken(0, ['SS', 2], 0, function () { + return ~~(this.millisecond() / 10); + }); + + addFormatToken(0, ['SSS', 3], 0, 'millisecond'); + addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; + }); + addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; + }); + addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; + }); + addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; + }); + addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; + }); + addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; + }); + + // ALIASES + + addUnitAlias('millisecond', 'ms'); + + // PRIORITY + + addUnitPriority('millisecond', 16); + + // PARSING + + addRegexToken('S', match1to3, match1); + addRegexToken('SS', match1to3, match2); + addRegexToken('SSS', match1to3, match3); + + var token, getSetMillisecond; + for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); + } + + function parseMs(input, array) { + array[MILLISECOND] = toInt(('0.' + input) * 1000); + } + + for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); + } + + getSetMillisecond = makeGetSet('Milliseconds', false); + + // FORMATTING + + addFormatToken('z', 0, 0, 'zoneAbbr'); + addFormatToken('zz', 0, 0, 'zoneName'); + + // MOMENTS + + function getZoneAbbr() { + return this._isUTC ? 'UTC' : ''; + } + + function getZoneName() { + return this._isUTC ? 'Coordinated Universal Time' : ''; + } + + var proto = Moment.prototype; + + proto.add = add; + proto.calendar = calendar$1; + proto.clone = clone; + proto.diff = diff; + proto.endOf = endOf; + proto.format = format; + proto.from = from; + proto.fromNow = fromNow; + proto.to = to; + proto.toNow = toNow; + proto.get = stringGet; + proto.invalidAt = invalidAt; + proto.isAfter = isAfter; + proto.isBefore = isBefore; + proto.isBetween = isBetween; + proto.isSame = isSame; + proto.isSameOrAfter = isSameOrAfter; + proto.isSameOrBefore = isSameOrBefore; + proto.isValid = isValid$2; + proto.lang = lang; + proto.locale = locale; + proto.localeData = localeData; + proto.max = prototypeMax; + proto.min = prototypeMin; + proto.parsingFlags = parsingFlags; + proto.set = stringSet; + proto.startOf = startOf; + proto.subtract = subtract; + proto.toArray = toArray; + proto.toObject = toObject; + proto.toDate = toDate; + proto.toISOString = toISOString; + proto.inspect = inspect; + if (typeof Symbol !== 'undefined' && Symbol.for != null) { + proto[Symbol.for('nodejs.util.inspect.custom')] = function () { + return 'Moment<' + this.format() + '>'; + }; + } + proto.toJSON = toJSON; + proto.toString = toString; + proto.unix = unix; + proto.valueOf = valueOf; + proto.creationData = creationData; + proto.eraName = getEraName; + proto.eraNarrow = getEraNarrow; + proto.eraAbbr = getEraAbbr; + proto.eraYear = getEraYear; + proto.year = getSetYear; + proto.isLeapYear = getIsLeapYear; + proto.weekYear = getSetWeekYear; + proto.isoWeekYear = getSetISOWeekYear; + proto.quarter = proto.quarters = getSetQuarter; + proto.month = getSetMonth; + proto.daysInMonth = getDaysInMonth; + proto.week = proto.weeks = getSetWeek; + proto.isoWeek = proto.isoWeeks = getSetISOWeek; + proto.weeksInYear = getWeeksInYear; + proto.weeksInWeekYear = getWeeksInWeekYear; + proto.isoWeeksInYear = getISOWeeksInYear; + proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear; + proto.date = getSetDayOfMonth; + proto.day = proto.days = getSetDayOfWeek; + proto.weekday = getSetLocaleDayOfWeek; + proto.isoWeekday = getSetISODayOfWeek; + proto.dayOfYear = getSetDayOfYear; + proto.hour = proto.hours = getSetHour; + proto.minute = proto.minutes = getSetMinute; + proto.second = proto.seconds = getSetSecond; + proto.millisecond = proto.milliseconds = getSetMillisecond; + proto.utcOffset = getSetOffset; + proto.utc = setOffsetToUTC; + proto.local = setOffsetToLocal; + proto.parseZone = setOffsetToParsedOffset; + proto.hasAlignedHourOffset = hasAlignedHourOffset; + proto.isDST = isDaylightSavingTime; + proto.isLocal = isLocal; + proto.isUtcOffset = isUtcOffset; + proto.isUtc = isUtc; + proto.isUTC = isUtc; + proto.zoneAbbr = getZoneAbbr; + proto.zoneName = getZoneName; + proto.dates = deprecate( + 'dates accessor is deprecated. Use date instead.', + getSetDayOfMonth + ); + proto.months = deprecate( + 'months accessor is deprecated. Use month instead', + getSetMonth + ); + proto.years = deprecate( + 'years accessor is deprecated. Use year instead', + getSetYear + ); + proto.zone = deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', + getSetZone + ); + proto.isDSTShifted = deprecate( + 'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', + isDaylightSavingTimeShifted + ); + + function createUnix(input) { + return createLocal(input * 1000); + } + + function createInZone() { + return createLocal.apply(null, arguments).parseZone(); + } + + function preParsePostFormat(string) { + return string; + } + + var proto$1 = Locale.prototype; + + proto$1.calendar = calendar; + proto$1.longDateFormat = longDateFormat; + proto$1.invalidDate = invalidDate; + proto$1.ordinal = ordinal; + proto$1.preparse = preParsePostFormat; + proto$1.postformat = preParsePostFormat; + proto$1.relativeTime = relativeTime; + proto$1.pastFuture = pastFuture; + proto$1.set = set; + proto$1.eras = localeEras; + proto$1.erasParse = localeErasParse; + proto$1.erasConvertYear = localeErasConvertYear; + proto$1.erasAbbrRegex = erasAbbrRegex; + proto$1.erasNameRegex = erasNameRegex; + proto$1.erasNarrowRegex = erasNarrowRegex; + + proto$1.months = localeMonths; + proto$1.monthsShort = localeMonthsShort; + proto$1.monthsParse = localeMonthsParse; + proto$1.monthsRegex = monthsRegex; + proto$1.monthsShortRegex = monthsShortRegex; + proto$1.week = localeWeek; + proto$1.firstDayOfYear = localeFirstDayOfYear; + proto$1.firstDayOfWeek = localeFirstDayOfWeek; + + proto$1.weekdays = localeWeekdays; + proto$1.weekdaysMin = localeWeekdaysMin; + proto$1.weekdaysShort = localeWeekdaysShort; + proto$1.weekdaysParse = localeWeekdaysParse; + + proto$1.weekdaysRegex = weekdaysRegex; + proto$1.weekdaysShortRegex = weekdaysShortRegex; + proto$1.weekdaysMinRegex = weekdaysMinRegex; + + proto$1.isPM = localeIsPM; + proto$1.meridiem = localeMeridiem; + + function get$1(format, index, field, setter) { + var locale = getLocale(), + utc = createUTC().set(setter, index); + return locale[field](utc, format); + } + + function listMonthsImpl(format, index, field) { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + + if (index != null) { + return get$1(format, index, field, 'month'); + } + + var i, + out = []; + for (i = 0; i < 12; i++) { + out[i] = get$1(format, i, field, 'month'); + } + return out; + } + + // () + // (5) + // (fmt, 5) + // (fmt) + // (true) + // (true, 5) + // (true, fmt, 5) + // (true, fmt) + function listWeekdaysImpl(localeSorted, format, index, field) { + if (typeof localeSorted === 'boolean') { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } else { + format = localeSorted; + index = format; + localeSorted = false; + + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } + + var locale = getLocale(), + shift = localeSorted ? locale._week.dow : 0, + i, + out = []; + + if (index != null) { + return get$1(format, (index + shift) % 7, field, 'day'); + } + + for (i = 0; i < 7; i++) { + out[i] = get$1(format, (i + shift) % 7, field, 'day'); + } + return out; + } + + function listMonths(format, index) { + return listMonthsImpl(format, index, 'months'); + } + + function listMonthsShort(format, index) { + return listMonthsImpl(format, index, 'monthsShort'); + } + + function listWeekdays(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); + } + + function listWeekdaysShort(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); + } + + function listWeekdaysMin(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); + } + + getSetGlobalLocale('en', { + eras: [ + { + since: '0001-01-01', + until: +Infinity, + offset: 1, + name: 'Anno Domini', + narrow: 'AD', + abbr: 'AD', + }, + { + since: '0000-12-31', + until: -Infinity, + offset: 1, + name: 'Before Christ', + narrow: 'BC', + abbr: 'BC', + }, + ], + dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal: function (number) { + var b = number % 10, + output = + toInt((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + }); + + // Side effect imports + + hooks.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + getSetGlobalLocale + ); + hooks.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + getLocale + ); + + var mathAbs = Math.abs; + + function abs() { + var data = this._data; + + this._milliseconds = mathAbs(this._milliseconds); + this._days = mathAbs(this._days); + this._months = mathAbs(this._months); + + data.milliseconds = mathAbs(data.milliseconds); + data.seconds = mathAbs(data.seconds); + data.minutes = mathAbs(data.minutes); + data.hours = mathAbs(data.hours); + data.months = mathAbs(data.months); + data.years = mathAbs(data.years); + + return this; + } + + function addSubtract$1(duration, input, value, direction) { + var other = createDuration(input, value); + + duration._milliseconds += direction * other._milliseconds; + duration._days += direction * other._days; + duration._months += direction * other._months; + + return duration._bubble(); + } + + // supports only 2.0-style add(1, 's') or add(duration) + function add$1(input, value) { + return addSubtract$1(this, input, value, 1); + } + + // supports only 2.0-style subtract(1, 's') or subtract(duration) + function subtract$1(input, value) { + return addSubtract$1(this, input, value, -1); + } + + function absCeil(number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } + } + + function bubble() { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, + minutes, + hours, + years, + monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if ( + !( + (milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0) + ) + ) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absFloor(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absFloor(seconds / 60); + data.minutes = minutes % 60; + + hours = absFloor(minutes / 60); + data.hours = hours % 24; + + days += absFloor(hours / 24); + + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + + return this; + } + + function daysToMonths(days) { + // 400 years have 146097 days (taking into account leap year rules) + // 400 years have 12 months === 4800 + return (days * 4800) / 146097; + } + + function monthsToDays(months) { + // the reverse of daysToMonths + return (months * 146097) / 4800; + } + + function as(units) { + if (!this.isValid()) { + return NaN; + } + var days, + months, + milliseconds = this._milliseconds; + + units = normalizeUnits(units); + + if (units === 'month' || units === 'quarter' || units === 'year') { + days = this._days + milliseconds / 864e5; + months = this._months + daysToMonths(days); + switch (units) { + case 'month': + return months; + case 'quarter': + return months / 3; + case 'year': + return months / 12; + } + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(monthsToDays(this._months)); + switch (units) { + case 'week': + return days / 7 + milliseconds / 6048e5; + case 'day': + return days + milliseconds / 864e5; + case 'hour': + return days * 24 + milliseconds / 36e5; + case 'minute': + return days * 1440 + milliseconds / 6e4; + case 'second': + return days * 86400 + milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': + return Math.floor(days * 864e5) + milliseconds; + default: + throw new Error('Unknown unit ' + units); + } + } + } + + // TODO: Use this.as('ms')? + function valueOf$1() { + if (!this.isValid()) { + return NaN; + } + return ( + this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6 + ); + } + + function makeAs(alias) { + return function () { + return this.as(alias); + }; + } + + var asMilliseconds = makeAs('ms'), + asSeconds = makeAs('s'), + asMinutes = makeAs('m'), + asHours = makeAs('h'), + asDays = makeAs('d'), + asWeeks = makeAs('w'), + asMonths = makeAs('M'), + asQuarters = makeAs('Q'), + asYears = makeAs('y'); + + function clone$1() { + return createDuration(this); + } + + function get$2(units) { + units = normalizeUnits(units); + return this.isValid() ? this[units + 's']() : NaN; + } + + function makeGetter(name) { + return function () { + return this.isValid() ? this._data[name] : NaN; + }; + } + + var milliseconds = makeGetter('milliseconds'), + seconds = makeGetter('seconds'), + minutes = makeGetter('minutes'), + hours = makeGetter('hours'), + days = makeGetter('days'), + months = makeGetter('months'), + years = makeGetter('years'); + + function weeks() { + return absFloor(this.days() / 7); + } + + var round = Math.round, + thresholds = { + ss: 44, // a few seconds to seconds + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month/week + w: null, // weeks to month + M: 11, // months to year + }; + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) { + var duration = createDuration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + weeks = round(duration.as('w')), + years = round(duration.as('y')), + a = + (seconds <= thresholds.ss && ['s', seconds]) || + (seconds < thresholds.s && ['ss', seconds]) || + (minutes <= 1 && ['m']) || + (minutes < thresholds.m && ['mm', minutes]) || + (hours <= 1 && ['h']) || + (hours < thresholds.h && ['hh', hours]) || + (days <= 1 && ['d']) || + (days < thresholds.d && ['dd', days]); + + if (thresholds.w != null) { + a = + a || + (weeks <= 1 && ['w']) || + (weeks < thresholds.w && ['ww', weeks]); + } + a = a || + (months <= 1 && ['M']) || + (months < thresholds.M && ['MM', months]) || + (years <= 1 && ['y']) || ['yy', years]; + + a[2] = withoutSuffix; + a[3] = +posNegDuration > 0; + a[4] = locale; + return substituteTimeAgo.apply(null, a); + } + + // This function allows you to set the rounding function for relative time strings + function getSetRelativeTimeRounding(roundingFunction) { + if (roundingFunction === undefined) { + return round; + } + if (typeof roundingFunction === 'function') { + round = roundingFunction; + return true; + } + return false; + } + + // This function allows you to set a threshold for relative time strings + function getSetRelativeTimeThreshold(threshold, limit) { + if (thresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return thresholds[threshold]; + } + thresholds[threshold] = limit; + if (threshold === 's') { + thresholds.ss = limit - 1; + } + return true; + } + + function humanize(argWithSuffix, argThresholds) { + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var withSuffix = false, + th = thresholds, + locale, + output; + + if (typeof argWithSuffix === 'object') { + argThresholds = argWithSuffix; + argWithSuffix = false; + } + if (typeof argWithSuffix === 'boolean') { + withSuffix = argWithSuffix; + } + if (typeof argThresholds === 'object') { + th = Object.assign({}, thresholds, argThresholds); + if (argThresholds.s != null && argThresholds.ss == null) { + th.ss = argThresholds.s - 1; + } + } + + locale = this.localeData(); + output = relativeTime$1(this, !withSuffix, th, locale); + + if (withSuffix) { + output = locale.pastFuture(+this, output); + } + + return locale.postformat(output); + } + + var abs$1 = Math.abs; + + function sign(x) { + return (x > 0) - (x < 0) || +x; + } + + function toISOString$1() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var seconds = abs$1(this._milliseconds) / 1000, + days = abs$1(this._days), + months = abs$1(this._months), + minutes, + hours, + years, + s, + total = this.asSeconds(), + totalSign, + ymSign, + daysSign, + hmsSign; + + if (!total) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : ''; + + totalSign = total < 0 ? '-' : ''; + ymSign = sign(this._months) !== sign(total) ? '-' : ''; + daysSign = sign(this._days) !== sign(total) ? '-' : ''; + hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : ''; + + return ( + totalSign + + 'P' + + (years ? ymSign + years + 'Y' : '') + + (months ? ymSign + months + 'M' : '') + + (days ? daysSign + days + 'D' : '') + + (hours || minutes || seconds ? 'T' : '') + + (hours ? hmsSign + hours + 'H' : '') + + (minutes ? hmsSign + minutes + 'M' : '') + + (seconds ? hmsSign + s + 'S' : '') + ); + } + + var proto$2 = Duration.prototype; + + proto$2.isValid = isValid$1; + proto$2.abs = abs; + proto$2.add = add$1; + proto$2.subtract = subtract$1; + proto$2.as = as; + proto$2.asMilliseconds = asMilliseconds; + proto$2.asSeconds = asSeconds; + proto$2.asMinutes = asMinutes; + proto$2.asHours = asHours; + proto$2.asDays = asDays; + proto$2.asWeeks = asWeeks; + proto$2.asMonths = asMonths; + proto$2.asQuarters = asQuarters; + proto$2.asYears = asYears; + proto$2.valueOf = valueOf$1; + proto$2._bubble = bubble; + proto$2.clone = clone$1; + proto$2.get = get$2; + proto$2.milliseconds = milliseconds; + proto$2.seconds = seconds; + proto$2.minutes = minutes; + proto$2.hours = hours; + proto$2.days = days; + proto$2.weeks = weeks; + proto$2.months = months; + proto$2.years = years; + proto$2.humanize = humanize; + proto$2.toISOString = toISOString$1; + proto$2.toString = toISOString$1; + proto$2.toJSON = toISOString$1; + proto$2.locale = locale; + proto$2.localeData = localeData; + + proto$2.toIsoString = deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', + toISOString$1 + ); + proto$2.lang = lang; + + // FORMATTING + + addFormatToken('X', 0, 0, 'unix'); + addFormatToken('x', 0, 0, 'valueOf'); + + // PARSING + + addRegexToken('x', matchSigned); + addRegexToken('X', matchTimestamp); + addParseToken('X', function (input, array, config) { + config._d = new Date(parseFloat(input) * 1000); + }); + addParseToken('x', function (input, array, config) { + config._d = new Date(toInt(input)); + }); + + //! moment.js + + hooks.version = '2.29.4'; + + setHookCallback(createLocal); + + hooks.fn = proto; + hooks.min = min; + hooks.max = max; + hooks.now = now; + hooks.utc = createUTC; + hooks.unix = createUnix; + hooks.months = listMonths; + hooks.isDate = isDate; + hooks.locale = getSetGlobalLocale; + hooks.invalid = createInvalid; + hooks.duration = createDuration; + hooks.isMoment = isMoment; + hooks.weekdays = listWeekdays; + hooks.parseZone = createInZone; + hooks.localeData = getLocale; + hooks.isDuration = isDuration; + hooks.monthsShort = listMonthsShort; + hooks.weekdaysMin = listWeekdaysMin; + hooks.defineLocale = defineLocale; + hooks.updateLocale = updateLocale; + hooks.locales = listLocales; + hooks.weekdaysShort = listWeekdaysShort; + hooks.normalizeUnits = normalizeUnits; + hooks.relativeTimeRounding = getSetRelativeTimeRounding; + hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; + hooks.calendarFormat = getCalendarFormat; + hooks.prototype = proto; + + // currently HTML5 input type only supports 24-hour formats + hooks.HTML5_FMT = { + DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // + DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // + DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // + DATE: 'YYYY-MM-DD', // + TIME: 'HH:mm', // + TIME_SECONDS: 'HH:mm:ss', // + TIME_MS: 'HH:mm:ss.SSS', // + WEEK: 'GGGG-[W]WW', // + MONTH: 'YYYY-MM', // + }; + + return hooks; + +}))); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/icons/default/icons.min.js b/idrocap_wa/webroot/js/tinymce/icons/default/icons.min.js new file mode 100644 index 0000000..15a8181 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/icons/default/icons.min.js @@ -0,0 +1 @@ +tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"accordion-toggle":'',accordion:'',"action-next":'',"action-prev":'',addtag:'',"ai-prompt":'',ai:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-code":'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',"math-equation":'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"export-pdf":'',"export-word":'',"import-word":'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"revision-history":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',send:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/langs/README.md b/idrocap_wa/webroot/js/tinymce/langs/README.md new file mode 100644 index 0000000..cd93d8c --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/langs/README.md @@ -0,0 +1,3 @@ +This is where language files should be placed. + +Please DO NOT translate these directly, use this service instead: https://crowdin.com/project/tinymce diff --git a/idrocap_wa/webroot/js/tinymce/langs/it.js b/idrocap_wa/webroot/js/tinymce/langs/it.js new file mode 100644 index 0000000..d92eacd --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/langs/it.js @@ -0,0 +1 @@ +tinymce.addI18n("it",{"#":"#","Accessibility":"Accessibilit\xe0","Accordion":"","Accordion body...":"","Accordion summary...":"","Action":"Azione","Activity":"Attivit\xe0","Address":"Indirizzo","Advanced":"Avanzate","Align":"Allinea","Align center":"Allinea al centro","Align left":"Allinea a sinistra","Align right":"Allinea a destra","Alignment":"Allineamento","Alignment {0}":"","All":"Tutto","Alternative description":"Descrizione alternativa","Alternative source":"Sorgente alternativa","Alternative source URL":"URL sorgente alternativa","Anchor":"Ancora","Anchor...":"Ancoraggio...","Anchors":"Ancoraggi","Animals and Nature":"Animali e natura","Arrows":"Frecce","B":"B","Background color":"Colore dello sfondo","Background color {0}":"","Black":"Nero","Block":"Blocco","Block {0}":"","Blockquote":"Citazione","Blocks":"Blocchi","Blue":"Blu","Blue component":"Componente blu","Body":"Corpo","Bold":"Grassetto","Border":"Bordo","Border color":"Colore del bordo","Border style":"Stile del bordo","Border width":"Larghezza del bordo","Bottom":"In basso","Browse files":"","Browse for an image":"Cerca un'immagine","Browse links":"","Bullet list":"Elenco puntato","Cancel":"Annulla","Caption":"Didascalia","Cell":"Cella","Cell padding":"Spaziatura interna celle","Cell properties":"Propriet\xe0 cella","Cell spacing":"Spaziatura tra celle","Cell styles":"Stili cella","Cell type":"Tipo di cella","Center":"Centro","Characters":"Caratteri","Characters (no spaces)":"Caratteri (senza spazi)","Circle":"Circolo","Class":"Classe","Clear formatting":"Cancella la formattazione","Close":"Chiudi","Code":"Codice","Code sample...":"Esempio di codice...","Code view":"Visualizza codice","Color Picker":"Selezione colori","Color swatch":"Campione di colore","Cols":"Colonne","Column":"Colonna","Column clipboard actions":"Azioni appunti colonna","Column group":"Gruppo di colonne","Column header":"Intestazione colonna","Constrain proportions":"Mantieni proporzioni","Copy":"Copia","Copy column":"Copia colonna","Copy row":"Copia riga","Could not find the specified string.":"Impossibile trovare la stringa specificata.","Could not load emojis":"Non posso caricare le emojis","Count":"Conteggio","Currency":"Valuta","Current window":"Finestra corrente","Custom color":"Colore personalizzato","Custom...":"Personalizzato...","Cut":"Taglia","Cut column":"Taglia colonna","Cut row":"Taglia riga","Dark Blue":"Blu scuro","Dark Gray":"Grigio scuro","Dark Green":"Verde scuro","Dark Orange":"Arancio scuro","Dark Purple":"Viola scuro","Dark Red":"Rosso scuro","Dark Turquoise":"Turchese scuro","Dark Yellow":"Giallo scuro","Dashed":"Trattini","Date/time":"Data/ora","Decrease indent":"Riduci rientro","Default":"Predefinito","Delete accordion":"","Delete column":"Elimina colonna","Delete row":"Elimina riga","Delete table":"Elimina tabella","Dimensions":"Dimensioni","Disc":"Disco","Div":"Div","Document":"Documento","Dotted":"Puntini","Double":"Doppio","Drop an image here":"Rilasciare un'immagine qui","Dropped file type is not supported":"Tipo di file non supportato","Edit":"Modifica","Embed":"Incorpora","Emojis":"Emojis","Emojis...":"Emojis...","Error":"Errore","Error: Form submit field collision.":"Errore: Conflitto di campi nel modulo inviato.","Error: No form element found.":"Errore: Nessun elemento di modulo trovato.","Extended Latin":"Latino esteso","Failed to initialize plugin: {0}":"Inizializzazione plugin fallita: {0}","Failed to load plugin url: {0}":"Caricamento URL plugin fallito: {0}","Failed to load plugin: {0} from url {1}":"Caricamento plugin fallito: {0} dall'URL {1}","Failed to upload image: {0}":"Caricamento immagine fallito: {0}","File":"File","Find":"Trova","Find (if searchreplace plugin activated)":"Trova (se \xe8 attivato l'apposito plugin)","Find and Replace":"Trova e sostituisci","Find and replace...":"Trova e sostituisci...","Find in selection":"Trova nella selezione","Find whole words only":"Trova solo parole intere","Flags":"Bandiere","Focus to contextual toolbar":"Imposta stato attivo per la barra degli strumenti contestuale","Focus to element path":"Imposta stato attivo per il percorso dell'elemento","Focus to menubar":"Imposta stato attivo per la barra dei menu","Focus to toolbar":"Imposta stato attivo per la barra degli strumenti","Font":"Carattere","Font size {0}":"","Font sizes":"Dimensioni font","Font {0}":"","Fonts":"Caratteri","Food and Drink":"Cibi e bevande","Footer":"Pi\xe8 di pagina","Format":"Formato","Format {0}":"","Formats":"Formati","Fullscreen":"A tutto schermo","G":"V","General":"Generali","Gray":"Grigio","Green":"Verde","Green component":"Componente verde","Groove":"Groove","Handy Shortcuts":"Scorciatoie utili","Header":"Intestazione","Header cell":"Cella d'intestazione","Heading 1":"Titolo 1","Heading 2":"Titolo 2","Heading 3":"Titolo 3","Heading 4":"Titolo 4","Heading 5":"Titolo 5","Heading 6":"Titolo 6","Headings":"Titoli","Height":"Altezza","Help":"Guida","Hex color code":"Colore esadecimale","Hidden":"Nascosto","Horizontal align":"Allineamento orizzontale","Horizontal line":"Linea orizzontale","Horizontal space":"Spazio orizzontale","ID":"ID","ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.":"ID dovrebbe iniziare con una lettera, seguita solo da lettere, numeri, trattini, punti, due punti.","Image is decorative":"L'immagine \xe8 decorativa","Image list":"Elenco immagini","Image title":"Titolo immagine","Image...":"Immagine...","ImageProxy HTTP error: Could not find Image Proxy":"Errore HTTP ImageProxy: impossibile trovare Image Proxy","ImageProxy HTTP error: Incorrect Image Proxy URL":"Errore HTTP ImageProxy: URL Image Proxy non corretto","ImageProxy HTTP error: Rejected request":"Errore HTTP ImageProxy: richiesta rifiutata","ImageProxy HTTP error: Unknown ImageProxy error":"Errore HTTP ImageProxy: errore sconosciuto","Increase indent":"Aumenta rientro","Inline":"In linea","Insert":"Inserisci","Insert Template":"Inserisci modello","Insert accordion":"","Insert column after":"Inserisci colonna dopo","Insert column before":"Inserisci colonna prima","Insert date/time":"Inserisci data/ora","Insert image":"Inserisci immagine","Insert link (if link plugin activated)":"Inserisci un collegamento (se \xe8 attivato l'apposito plugin)","Insert row after":"Inserisci riga dopo","Insert row before":"Inserisci riga prima","Insert table":"Inserisci tabella","Insert template...":"Inserisci modello...","Insert video":"Inserisci video","Insert/Edit code sample":"Inserisci/modifica esempio di codice","Insert/edit image":"Inserisci/modifica immagine","Insert/edit link":"Inserisci/modifica collegamento","Insert/edit media":"Inserisci/modifica oggetti multimediali","Insert/edit video":"Inserisci/modifica video","Inset":"Inserto","Invalid hex color code: {0}":"Codice esadecimale colore non valido: {0}","Invalid input":"Dato non valido","Italic":"Corsivo","Justify":"Giustifica","Keyboard Navigation":"Navigazione tramite tastiera","Language":"Lingua","Learn more...":"Maggiori informazioni...","Left":"Sinistra","Left to right":"Da sinistra a destra","Light Blue":"Azzurro","Light Gray":"Grigio chiaro","Light Green":"Verde chiaro","Light Purple":"Viola chiaro","Light Red":"Rosso chiaro","Light Yellow":"Giallo chiaro","Line height":"Altezza linea","Link list":"Elenco collegamenti","Link...":"Collegamento...","List Properties":"Propriet\xe0 Lista","List properties...":"Propriet\xe0 lista...","Loading emojis...":"Caricamento emojis...","Loading...":"Lettura in corso...","Lower Alpha":"Alfabetico minuscolo","Lower Greek":"Greco minuscolo","Lower Roman":"Romano minuscolo","Match case":"Maiuscole/minuscole","Mathematical":"Caratteri matematici","Media poster (Image URL)":"Poster dell'oggetto multimediale (URL dell'immagine)","Media...":"Oggetto multimediale...","Medium Blue":"Blu medio","Medium Gray":"Grigio medio","Medium Purple":"Viola medio","Merge cells":"Unisci le celle","Middle":"Centrato","Midnight Blue":"Blu notte","More...":"Altro\u2026","Name":"Nome","Navy Blue":"Blu scuro","New document":"Nuovo documento","New window":"Nuova finestra","Next":"Avanti","No":"No","No alignment":"Senza allineamento","No color":"Nessun colore","Nonbreaking space":"Spazio indivisibile","None":"Nessuno","Numbered list":"Elenco numerato","OR":"OPPURE","Objects":"Oggetti","Ok":"OK","Open help dialog":"Apri la finestra di aiuto","Open link":"Apri link","Open link in...":"Apri collegamento in...","Open popup menu for split buttons":"Apri il menu a comparsa per i pulsanti divisi","Orange":"Arancio","Outset":"Inizio","Page break":"Interruzione di pagina","Paragraph":"Paragrafo","Paste":"Incolla","Paste as text":"Incolla senza formattazioni","Paste column after":"Inserisci colonna dopo","Paste column before":"Inserisci colonna prima","Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.":"Incolla \xe8 in modalit\xe0 testo normale. I contenuti saranno incollati come testo normale se non viene disattivata questa opzione.","Paste or type a link":"Incolla o digita un collegamento","Paste row after":"Incolla riga dopo","Paste row before":"Incolla riga prima","Paste your embed code below:":"Incolla il codice d'incorporamento di seguito:","People":"Persone","Plugins":"Plugin","Plugins installed ({0}):":"Plugin installati ({0}):","Powered by {0}":"Con tecnologia {0}","Pre":"Pre","Preferences":"Preferenze","Preformatted":"Preformattato","Premium plugins:":"Plugin Premium:","Press the Up and Down arrow keys to resize the editor.":"","Press the arrow keys to resize the editor.":"","Press {0} for help":"","Preview":"Anteprima","Previous":"Indietro","Print":"Stampa","Print...":"Stampa...","Purple":"Viola","Quotations":"Citazioni","R":"R","Range 0 to 255":"Intervallo da 0 a 255","Red":"Rosso","Red component":"Componente rosso","Redo":"Ripristina","Remove":"Rimuovi","Remove color":"Rimuovi colore","Remove link":"Rimuovi collegamento","Replace":"Sostituisci","Replace all":"Sostituisci tutto","Replace with":"Sostituisci con","Resize":"Ridimensiona","Restore last draft":"Ripristina l'ultima bozza","Reveal or hide additional toolbar items":"","Rich Text Area":"Area di testo ricco","Rich Text Area. Press ALT-0 for help.":"Area di testo RTF. Premere ALT-0 per la guida.","Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help":"Area di testo RTF. Premere ALT-F9 per il menu. Premere ALT-F10 per la barra degli strumenti. Premere ALT-0 per la guida.","Ridge":"Ridge","Right":"Destra","Right to left":"Da destra a sinistra","Row":"Riga","Row clipboard actions":"Azioni appunti riga","Row group":"Gruppo di righe","Row header":"Intestazione riga","Row properties":"Propriet\xe0 della riga","Row type":"Tipo di riga","Rows":"Righe","Save":"Salva","Save (if save plugin activated)":"Salva (se \xe8 attivato l'apposito plugin)","Scope":"Ambito","Search":"Cerca","Select all":"Seleziona tutto","Select...":"Seleziona...","Selection":"Selezione","Shortcut":"Collegamento","Show blocks":"Mostra blocchi","Show caption":"Mostra didascalia","Show invisible characters":"Mostra caratteri invisibili","Size":"Dimensione carattere","Solid":"Pieno","Source":"Fonte","Source code":"Codice sorgente","Special Character":"Carattere Speciale","Special character...":"Carattere speciale...","Split cell":"Dividi la cella","Square":"Quadrato","Start list at number":"La lista inizia con il numero","Strikethrough":"Barrato","Style":"Stile","Subscript":"Pedice","Superscript":"Apice","Switch to or from fullscreen mode":"Attiva/disattiva la modalit\xe0 schermo intero","Symbols":"Simboli","System Font":"Carattere di sistema","Table":"Tabella","Table caption":"Titolo tabella","Table properties":"Propriet\xe0 della tabella","Table styles":"Stili tabella","Template":"Modello","Templates":"Modelli","Text":"Testo","Text color":"Colore testo","Text color {0}":"","Text to display":"Testo da visualizzare","The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?":"L'URL inserito sembra essere un indirizzo email. Si vuole aggiungere il necessario prefisso mailto:?","The URL you entered seems to be an external link. Do you want to add the required http:// prefix?":"L'URL inserito sembra essere un collegamento esterno. Si vuole aggiungere il necessario prefisso http://?","The URL you entered seems to be an external link. Do you want to add the required https:// prefix?":"L'URL inserito sembra essere un collegamento esterno. Si vuole aggiungere il necessario prefisso http://?","Title":"Titolo","To open the popup, press Shift+Enter":"Per aprire il popup, premere Shift+Invio","Toggle accordion":"","Tools":"Strumenti","Top":"In alto","Travel and Places":"Viaggi e luoghi","Turquoise":"Turchese","Underline":"Sottolineato","Undo":"Annulla","Upload":"Carica","Uploading image":"Caricamento immagine","Upper Alpha":"Alfabetico maiuscolo","Upper Roman":"Romano maiuscolo","Url":"URL","User Defined":"Definito dall'utente","Valid":"Valido","Version":"Versione","Vertical align":"Allineamento verticale","Vertical space":"Spazio verticale","View":"Visualizza","Visual aids":"Aiuti visivi","Warn":"Avviso","White":"Bianco","Width":"Larghezza","Word count":"Conteggio parole","Words":"Parole","Words: {0}":"Parole: {0}","Yellow":"Giallo","Yes":"S\xec","You are using {0}":"Si sta utilizzando {0}","You have unsaved changes are you sure you want to navigate away?":"Ci sono modifiche non salvate, si \xe8 sicuro di volere uscire?","Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":"Il browser non supporta l'accesso diretto alla cartella degli appunti. Usare i tasti di scelta rapida Ctrl+X/C/V.","alignment":"allineamento","austral sign":"simbolo dell'austral","cedi sign":"simbolo del cedi","colon sign":"simbolo del col\xf3n","cruzeiro sign":"simbolo del cruzeiro","currency sign":"simbolo di valuta","dollar sign":"simbolo del dollaro","dong sign":"simbolo del dong","drachma sign":"simbolo della dracma","euro-currency sign":"simbolo dell'euro","example":"esempio","formatting":"formattazione","french franc sign":"simbolo del franco francese","german penny symbol":"simbolo del pfennig tedesco","guarani sign":"simbolo del guaran\xec","history":"cronologia","hryvnia sign":"simbolo della hryvnia","indentation":"indentazione","indian rupee sign":"simbolo della rup\xeca indiana","kip sign":"simbolo del kip","lira sign":"simbolo della lira","livre tournois sign":"simbolo della lira di Tours","manat sign":"simbolo del manat","mill sign":"simbolo del mill","naira sign":"simbolo della naira","new sheqel sign":"simbolo del nuovo shekel","nordic mark sign":"simbolo del marco nordico","peseta sign":"simbolo della peseta","peso sign":"simbolo del peso","ruble sign":"simbolo del rublo","rupee sign":"simbolo della rup\xeca","spesmilo sign":"simbolo dello spesmilo","styles":"stili","tenge sign":"simbolo del tenge","tugrik sign":"simbolo del tugrik","turkish lira sign":"simbolo della lira turca","won sign":"simbolo del won","yen character":"simbolo dello yen","yen/yuan character variant one":"simbolo yen/yuan variante uno","yuan character":"simbolo dello yuan","yuan character, in hong kong and taiwan":"simbolo dello yuan, Hong Kong e Taiwan","{0} characters":"{0} caratteri","{0} columns, {1} rows":"","{0} words":"{0} parole"}); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/license.md b/idrocap_wa/webroot/js/tinymce/license.md new file mode 100644 index 0000000..70454a6 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/license.md @@ -0,0 +1,6 @@ +# Software License Agreement + +**TinyMCE** – [](https://github.com/tinymce/tinymce) +Copyright (c) 2024, Ephox Corporation DBA Tiny Technologies, Inc. + +Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). diff --git a/idrocap_wa/webroot/js/tinymce/models/dom/model.min.js b/idrocap_wa/webroot/js/tinymce/models/dom/model.min.js new file mode 100644 index 0000000..6e08210 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/models/dom/model.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),s=t("object"),l=t("array"),a=n(null),c=o("boolean"),i=n(void 0),m=e=>!(e=>null==e)(e),d=o("function"),u=o("number"),f=()=>{},g=e=>()=>e,h=e=>e,p=(e,t)=>e===t;function b(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const w=e=>t=>!e(t),v=e=>e(),y=g(!1),x=g(!0);class C{constructor(e,t){this.tag=e,this.value=t}static some(e){return new C(!0,e)}static none(){return C.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?C.some(e(this.value)):C.none()}bind(e){return this.tag?e(this.value):C.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:C.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return m(e)?C.some(e):C.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}C.singletonNone=new C(!1);const T=Array.prototype.slice,S=Array.prototype.indexOf,R=Array.prototype.push,D=(e,t)=>{return o=e,n=t,S.call(o,n)>-1;var o,n},O=(e,t)=>{for(let o=0,n=e.length;o{const o=[];for(let n=0;n{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[],n=[];for(let r=0,s=e.length;r{const o=[];for(let n=0,r=e.length;n(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),A=(e,t,o)=>(N(e,((e,n)=>{o=t(o,e,n)})),o),L=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;oM(E(e,t)),P=(e,t)=>{for(let o=0,n=e.length;o{const o={};for(let n=0,r=e.length;nt>=0&&tF(e,0),$=e=>F(e,e.length-1),V=(e,t)=>{for(let o=0;o{const o=q(e);for(let n=0,r=o.length;nY(e,((e,o)=>({k:o,v:t(e,o)}))),Y=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},J=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},Q=e=>J(e,h),X=(e,t)=>U.call(e,t),Z="undefined"!=typeof window?window:Function("return this;")(),ee=(e,t)=>((e,t)=>{let o=null!=t?t:Z;for(let t=0;t{const t=ee("ownerDocument.defaultView",e);return s(e)&&((e=>((e,t)=>{const o=((e,t)=>ee(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(te(e).constructor.name))},ne=e=>e.dom.nodeName.toLowerCase(),re=e=>e.dom.nodeType,se=e=>t=>re(t)===e,le=e=>8===re(e)||"#comment"===ne(e),ae=e=>ce(e)&&oe(e.dom),ce=se(1),ie=se(3),me=se(9),de=se(11),ue=e=>t=>ce(t)&&ne(t)===e,fe=(e,t,o)=>{if(!(r(o)||c(o)||u(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},ge=(e,t,o)=>{fe(e.dom,t,o)},he=(e,t)=>{const o=e.dom;G(t,((e,t)=>{fe(o,t,e)}))},pe=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},be=(e,t)=>C.from(pe(e,t)),we=(e,t)=>{e.dom.removeAttribute(t)},ve=e=>A(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),ye=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},xe={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return ye(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return ye(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return ye(o)},fromDom:ye,fromPoint:(e,t,o)=>C.from(e.dom.elementFromPoint(t,o)).map(ye)},Ce=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Te=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Se=(e,t)=>{const o=void 0===t?document:t.dom;return Te(o)?C.none():C.from(o.querySelector(e)).map(xe.fromDom)},Re=(e,t)=>e.dom===t.dom,De=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Oe=Ce,ke=e=>xe.fromDom(e.dom.ownerDocument),Ee=e=>me(e)?e:ke(e),Ne=e=>C.from(e.dom.parentNode).map(xe.fromDom),Be=e=>C.from(e.dom.parentElement).map(xe.fromDom),_e=(e,t)=>{const o=d(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=xe.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},ze=e=>C.from(e.dom.previousSibling).map(xe.fromDom),Ae=e=>C.from(e.dom.nextSibling).map(xe.fromDom),Le=e=>E(e.dom.childNodes,xe.fromDom),We=(e,t)=>{const o=e.dom.childNodes;return C.from(o[t]).map(xe.fromDom)},Me=(e,t)=>{Ne(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},je=(e,t)=>{Ae(e).fold((()=>{Ne(e).each((e=>{Ie(e,t)}))}),(e=>{Me(e,t)}))},Pe=(e,t)=>{const o=(e=>We(e,0))(e);o.fold((()=>{Ie(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Ie=(e,t)=>{e.dom.appendChild(t.dom)},Fe=(e,t)=>{Me(e,t),Ie(t,e)},He=(e,t)=>{N(t,((o,n)=>{const r=0===n?e:t[n-1];je(r,o)}))},$e=(e,t)=>{N(t,(t=>{Ie(e,t)}))},Ve=e=>{e.dom.textContent="",N(Le(e),(e=>{qe(e)}))},qe=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Ue=e=>{const t=Le(e);t.length>0&&He(e,t),qe(e)},Ge=(e,t)=>xe.fromDom(e.dom.cloneNode(t)),Ke=e=>Ge(e,!1),Ye=e=>Ge(e,!0),Je=(e,t)=>{const o=xe.fromTag(t),n=ve(e);return he(o,n),o},Qe=["tfoot","thead","tbody","colgroup"],Xe=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Ze=(e,t,o)=>({element:e,cells:t,section:o}),et=(e,t,o)=>({element:e,isNew:t,isLocked:o}),tt=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),ot=e=>xe.fromDom(e.dom.host),nt=e=>{const t=ie(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=(e=>xe.fromDom(e.dom.getRootNode()))(e);return de(o=t)&&m(o.dom.host)?C.some(t):C.none();var o})(xe.fromDom(t)).fold((()=>o.body.contains(t)),(n=nt,r=ot,e=>n(r(e))));var n,r},rt=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return xe.fromDom(t)},st=(e,t)=>{let o=[];return N(Le(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(st(e,t))})),o},lt=(e,t,o)=>((e,o,n)=>_(_e(e,n),(e=>Ce(e,t))))(e,0,o),at=(e,t)=>((e,o)=>_(Le(e),(e=>Ce(e,t))))(e),ct=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Te(o)?[]:E(o.querySelectorAll(e),xe.fromDom)})(t,e);var it=(e,t,o,n,r)=>e(o,n)?C.some(o):d(r)&&r(o)?C.none():t(o,n,r);const mt=(e,t,o)=>{let n=e.dom;const r=d(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=xe.fromDom(n);if(t(e))return C.some(e);if(r(e))break}return C.none()},dt=(e,t,o)=>it(((e,t)=>t(e)),mt,e,t,o),ut=(e,t,o)=>mt(e,(e=>Ce(e,t)),o),ft=(e,t)=>((e,o)=>L(e.dom.childNodes,(e=>{return o=xe.fromDom(e),Ce(o,t);var o})).map(xe.fromDom))(e),gt=(e,t)=>Se(t,e),ht=(e,t,o)=>it(((e,t)=>Ce(e,t)),ut,e,t,o),pt=(e,t,o=p)=>e.exists((e=>o(e,t))),bt=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?C.some(t):C.none(),vt=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,yt=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!i(n)||r+t.length<=n)},xt=(e,t)=>vt(e,t,0),Ct=(e,t)=>vt(e,t,e.length-t.length),Tt=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),St=e=>e.length>0,Rt=e=>void 0!==e.style&&d(e.style.getPropertyValue),Dt=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);Rt(e)&&e.style.setProperty(t,o)},Ot=(e,t,o)=>{const n=e.dom;Dt(n,t,o)},kt=(e,t)=>{const o=e.dom;G(t,((e,t)=>{Dt(o,t,e)}))},Et=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||nt(e)?n:Nt(o,t)},Nt=(e,t)=>Rt(e)?e.style.getPropertyValue(t):"",Bt=(e,t)=>{const o=e.dom,n=Nt(o,t);return C.from(n).filter((e=>e.length>0))},_t=(e,t)=>{((e,t)=>{Rt(e)&&e.style.removeProperty(t)})(e.dom,t),pt(be(e,"style").map(Tt),"")&&we(e,"style")},zt=(e,t,o=0)=>be(e,t).map((e=>parseInt(e,10))).getOr(o),At=(e,t)=>zt(e,t,1),Lt=e=>ue("col")(e)?zt(e,"span",1)>1:At(e,"colspan")>1,Wt=(e,t)=>parseInt(Et(e,t),10),Mt=g(10),jt=g(10),Pt=(e,t)=>It(e,t,x),It=(e,t,o)=>j(Le(e),(e=>Ce(e,t)?o(e)?[e]:[]:It(e,t,o))),Ft=(e,t)=>((e,t,o=y)=>o(t)?C.none():D(e,ne(t))?C.some(t):ut(t,e.join(","),(e=>Ce(e,"table")||o(e))))(["td","th"],e,t),Ht=e=>Pt(e,"th,td"),$t=e=>Ce(e,"colgroup")?at(e,"col"):j(Ut(e),(e=>at(e,"col"))),Vt=(e,t)=>ht(e,"table",t),qt=e=>Pt(e,"tr"),Ut=e=>Vt(e).fold(g([]),(e=>at(e,"colgroup"))),Gt=(e,t)=>E(e,(e=>{if("colgroup"===ne(e)){const t=E($t(e),(e=>{const t=zt(e,"span",1);return Xe(e,1,t)}));return Ze(e,t,"colgroup")}{const o=E(Ht(e),(e=>{const t=zt(e,"rowspan",1),o=zt(e,"colspan",1);return Xe(e,t,o)}));return Ze(e,o,t(e))}})),Kt=e=>Ne(e).map((e=>{const t=ne(e);return(e=>D(Qe,e))(t)?t:"tbody"})).getOr("tbody"),Yt=e=>{const t=qt(e),o=[...Ut(e),...t];return Gt(o,Kt)},Jt=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},Qt=()=>Xt(0,0),Xt=(e,t)=>({major:e,minor:t}),Zt={nu:Xt,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?Qt():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return Xt(n(1),n(2))})(e,o)},unknown:Qt},eo=(e,t)=>{const o=String(t).toLowerCase();return L(e,(e=>e.search(o)))},to=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,oo=e=>t=>yt(t,e),no=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>yt(e,"edge/")&&yt(e,"chrome")&&yt(e,"safari")&&yt(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,to],search:e=>yt(e,"chrome")&&!yt(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>yt(e,"msie")||yt(e,"trident")},{name:"Opera",versionRegexes:[to,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:oo("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:oo("firefox")},{name:"Safari",versionRegexes:[to,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(yt(e,"safari")||yt(e,"mobile/"))&&yt(e,"applewebkit")}],ro=[{name:"Windows",search:oo("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>yt(e,"iphone")||yt(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:oo("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:oo("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:oo("linux"),versionRegexes:[]},{name:"Solaris",search:oo("sunos"),versionRegexes:[]},{name:"FreeBSD",search:oo("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:oo("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],so={browsers:g(no),oses:g(ro)},lo="Edge",ao="Chromium",co="Opera",io="Firefox",mo="Safari",uo=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(lo),isChromium:n(ao),isIE:n("IE"),isOpera:n(co),isFirefox:n(io),isSafari:n(mo)}},fo=()=>uo({current:void 0,version:Zt.unknown()}),go=uo,ho=(g(lo),g(ao),g("IE"),g(co),g(io),g(mo),"Windows"),po="Android",bo="Linux",wo="macOS",vo="Solaris",yo="FreeBSD",xo="ChromeOS",Co=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(ho),isiOS:n("iOS"),isAndroid:n(po),isMacOS:n(wo),isLinux:n(bo),isSolaris:n(vo),isFreeBSD:n(yo),isChromeOS:n(xo)}},To=()=>Co({current:void 0,version:Zt.unknown()}),So=Co,Ro=(g(ho),g("iOS"),g(po),g(bo),g(wo),g(vo),g(yo),g(xo),e=>window.matchMedia(e).matches);let Do=Jt((()=>((e,t,o)=>{const n=so.browsers(),r=so.oses(),s=t.bind((e=>((e,t)=>V(t.brands,(t=>{const o=t.brand.toLowerCase();return L(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:Zt.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>eo(e,t).map((e=>{const o=Zt.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(fo,go),l=((e,t)=>eo(e,t).map((e=>{const o=Zt.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(To,So),a=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),s=e.isiOS()&&!r,l=e.isiOS()||e.isAndroid(),a=l||n("(pointer:coarse)"),c=r||!s&&l&&n("(min-device-width:768px)"),i=s||l&&!c,m=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),d=!i&&!c&&!m;return{isiPad:g(r),isiPhone:g(s),isTablet:g(c),isPhone:g(i),isTouch:g(a),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(m),isDesktop:g(d)}})(l,s,e,o);return{browser:s,os:l,deviceType:a}})(window.navigator.userAgent,C.from(window.navigator.userAgentData),Ro)));const Oo=()=>Do(),ko=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=Et(o,e);return parseFloat(t)||0}return n},n=(e,t)=>A(t,((t,o)=>{const n=Et(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!u(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;Rt(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},Eo=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?C.none():C.some(t)})(e).getOr(t))(Et(e,t),o),No=ko("width",(e=>e.dom.offsetWidth)),Bo=e=>No.get(e),_o=e=>No.getOuter(e),zo=e=>((e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-Eo(e,`padding-${o}`,0)-Eo(e,`padding-${n}`,0)-Eo(e,`border-${o}-width`,0)-Eo(e,`border-${n}-width`,0))(e,n,"left","right")})(e,"content-box"),Ao=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),s=n.slice(t),l=r.concat(o).concat(s);return Mo(e,l)},Lo=(e,t,o)=>Ao(e,t,[o]),Wo=(e,t,o)=>{e.cells[t]=o},Mo=(e,t)=>tt(e.element,t,e.section,e.isNew),jo=(e,t)=>e.cells[t],Po=(e,t)=>jo(e,t).element,Io=e=>e.cells.length,Fo=e=>{const t=B(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},Ho=(e,t,o)=>{const n=E(e.cells,o);return tt(t(e.element),n,e.section,!0)},$o="data-snooker-locked-cols",Vo=e=>be(e,$o).bind((e=>C.from(e.match(/\d+/g)))).map((e=>I(e,x))),qo=e=>{const t=A(Fo(e).rows,((e,t)=>(N(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=J(t,((e,t)=>parseInt(t,10)));return((e,t)=>{const o=T.call(e,0);return o.sort(void 0),o})(o)},Uo=(e,t)=>e+","+t,Go=(e,t)=>{const o=j(e.all,(e=>e.cells));return _(o,t)},Ko=e=>{const t={},o=[],n=H(e).map((e=>e.element)).bind(Vt).bind(Vo).getOr({});let r=0,s=0,l=0;const{pass:a,fail:c}=B(e,(e=>"colgroup"===e.section));N(c,(e=>{const a=[];N(e.cells,(e=>{let o=0;for(;void 0!==t[Uo(l,o)];)o++;const r=((e,t)=>X(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),c=((e,t,o,n,r,s)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:s}))(e.element,e.rowspan,e.colspan,l,o,r);for(let n=0;n{const t=(e=>{const t={};let o=0;return N(e.cells,(e=>{const n=e.colspan;k(n,(r=>{const s=o+r;t[s]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,s)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,Q(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),d=((e,t)=>({rows:e,columns:t}))(r,s);return{grid:d,access:t,all:o,columns:i,colgroups:m}},Yo=e=>{const t=Yt(e);return Ko(t)},Jo=Ko,Qo=(e,t,o)=>C.from(e.access[Uo(t,o)]),Xo=(e,t,o)=>{const n=Go(e,(e=>o(t,e.element)));return n.length>0?C.some(n[0]):C.none()},Zo=Go,en=e=>j(e.all,(e=>e.cells)),tn=e=>Q(e.columns),on=e=>q(e.columns).length>0,nn=(e,t)=>C.from(e.columns[t]),rn=(e,t=x)=>{const o=e.grid,n=k(o.columns,h),r=k(o.rows,h);return E(n,(o=>sn((()=>j(r,(t=>Qo(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>Qo(e,0,o)))))},sn=(e,t,o)=>{const n=e();return L(n,t).orThunk((()=>C.from(n[0]).orThunk(o))).map((e=>e.element))},ln=e=>{const t=e.grid,o=k(t.rows,h),n=k(t.columns,h);return E(o,(t=>sn((()=>j(n,(o=>Qo(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>Qo(e,t,0)))))},an=(e,t)=>o=>"rtl"===cn(o)?t:e,cn=e=>"rtl"===Et(e,"direction")?"rtl":"ltr",mn=ko("height",(e=>{const t=e.dom;return nt(e)?t.getBoundingClientRect().height:t.offsetHeight})),dn=e=>mn.get(e),un=e=>mn.getOuter(e),fn=(e,t)=>({left:e,top:t,translate:(o,n)=>fn(e+o,t+n)}),gn=fn,hn=(e,t)=>void 0!==e?e:void 0!==t?t:0,pn=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return gn(o.offsetLeft,o.offsetTop);const s=hn(null==n?void 0:n.pageYOffset,r.scrollTop),l=hn(null==n?void 0:n.pageXOffset,r.scrollLeft),a=hn(r.clientTop,o.clientTop),c=hn(r.clientLeft,o.clientLeft);return bn(e).translate(l-c,s-a)},bn=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?gn(o.offsetLeft,o.offsetTop):nt(e)?(e=>{const t=e.getBoundingClientRect();return gn(t.left,t.top)})(t):gn(0,0)},wn=(e,t)=>({row:e,y:t}),vn=(e,t)=>({col:e,x:t}),yn=e=>pn(e).left+_o(e),xn=e=>pn(e).left,Cn=(e,t)=>vn(e,xn(t)),Tn=(e,t)=>vn(e,yn(t)),Sn=e=>pn(e).top,Rn=(e,t)=>wn(e,Sn(t)),Dn=(e,t)=>wn(e,Sn(t)+un(t)),On=(e,t,o)=>{if(0===o.length)return[];const n=E(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},kn={delta:h,positions:e=>On(Rn,Dn,e),edge:Sn},En=an({delta:h,edge:xn,positions:e=>On(Cn,Tn,e)},{delta:e=>-e,edge:yn,positions:e=>On(Tn,Cn,e)}),Nn={delta:(e,t)=>En(t).delta(e,t),positions:(e,t)=>En(t).positions(e,t),edge:e=>En(e).edge(e)},Bn={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},_n=(()=>{const e="[0-9]+",t="[eE][+-]?"+e,o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),zn=/(\d+(\.\d+)?)%/,An=/(\d+(\.\d+)?)px|em/,Ln=ue("col"),Wn=ue("tr"),Mn=(e,t,o)=>{const n=Be(e).getOrThunk((()=>rt(ke(e))));return t(e)/o(n)*100},jn=(e,t)=>{Ot(e,"width",t+"px")},Pn=(e,t)=>{Ot(e,"width",t+"%")},In=(e,t)=>{Ot(e,"height",t+"px")},Fn=e=>{const t=(e=>{return Eo(t=e,"height",t.dom.offsetHeight)+"px";var t})(e);return t?((e,t,o,n)=>{const r=parseFloat(e);return Ct(e,"%")&&"table"!==ne(t)?((e,t,o,n)=>{const r=Vt(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r})(t,e,dn,In):dn(e)},Hn=(e,t)=>Bt(e,t).orThunk((()=>be(e,t).map((e=>e+"px")))),$n=e=>Hn(e,"width"),Vn=e=>Mn(e,Bo,zo),qn=e=>{return Ln(e)?Bo(e):Eo(t=e,"width",t.dom.offsetWidth);var t},Un=e=>Wn(e)?dn(e):((e,t,o)=>o(e)/At(e,"rowspan"))(e,0,Fn),Gn=(e,t,o)=>{Ot(e,"width",t+o)},Kn=e=>Mn(e,Bo,zo)+"%",Yn=g(zn),Jn=ue("col"),Qn=e=>$n(e).getOrThunk((()=>qn(e)+"px")),Xn=e=>{return(t=e,Hn(t,"height")).getOrThunk((()=>Un(e)+"px"));var t},Zn=(e,t,o,n,r,s)=>e.filter(n).fold((()=>s(((e,t)=>{if(t<0||t>=e.length-1)return C.none();const o=e[t].fold((()=>{const o=(e=>{const t=T.call(e,0);return t.reverse(),t})(e.slice(0,t));return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))})(o,t))),(e=>r(e))),er=(e,t,o,n)=>{const r=rn(e),s=on(e)?(e=>E(tn(e),(e=>C.from(e.element))))(e):r,l=[C.some(Nn.edge(t))].concat(E(Nn.positions(r,t),(e=>e.map((e=>e.x))))),a=w(Lt);return E(s,((e,t)=>Zn(e,t,l,a,(e=>{if((e=>{const t=Oo().browser,o=t.isChromium()||t.isFirefox();return!Jn(e)||o})(e))return o(e);{const e=null!=(s=r[t])?h(s):C.none();return Zn(e,t,l,a,(e=>n(C.some(Bo(e)))),n)}var s}),n)))},tr=e=>e.map((e=>e+"px")).getOr(""),or=(e,t,o)=>er(e,t,qn,(e=>e.getOrThunk(o.minCellWidth))),nr=(e,t,o,n)=>{const r=ln(e),s=E(e.all,(e=>C.some(e.element))),l=[C.some(kn.edge(t))].concat(E(kn.positions(r,t),(e=>e.map((e=>e.y)))));return E(s,((e,t)=>Zn(e,t,l,x,o,n)))},rr=(e,t)=>()=>nt(e)?t(e):parseFloat(Bt(e,"width").getOr("0")),sr=e=>{const t=rr(e,(e=>parseFloat(Kn(e)))),o=rr(e,Bo);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>er(e,t,Vn,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>Mt()/o()*100,setElementWidth:Pn,adjustTableWidth:o=>{const n=t();Pn(e,n+o/100*n)},isRelative:!0,label:"percent"}},lr=e=>{const t=rr(e,Bo);return{width:t,pixelWidth:t,getWidths:(t,o)=>or(t,e,o),getCellDelta:h,singleColumnWidth:(e,t)=>[Math.max(Mt(),e+t)-e],minCellWidth:Mt,setElementWidth:jn,adjustTableWidth:o=>{const n=t()+o;jn(e,n)},isRelative:!1,label:"pixel"}},ar=e=>$n(e).fold((()=>(e=>{const t=rr(e,Bo),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>or(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:f,adjustTableWidth:f,isRelative:!0,label:"none"}})(e)),(t=>((e,t)=>null!==Yn().exec(t)?sr(e):lr(e))(e,t))),cr=lr,ir=sr,mr=(e,t,o)=>{const n=e[o].element,r=xe.fromTag("td");Ie(r,xe.fromTag("br")),(t?Ie:Pe)(n,r)},dr=((e,t)=>{const o=t=>e(t)?C.from(t.dom.nodeValue):C.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(ie),ur=e=>dr.get(e),fr=e=>dr.getOption(e),gr=(e,t)=>dr.set(e,t),hr=e=>"img"===ne(e)?1:fr(e).fold((()=>Le(e).length),(e=>e.length)),pr=["img","br"],br=e=>fr(e).filter((e=>0!==e.trim().length||e.indexOf("\xa0")>-1)).isSome()||D(pr,ne(e))||(e=>ae(e)&&"false"===pe(e,"contenteditable"))(e),wr=e=>((e,t)=>{const o=e=>{for(let n=0;nyr(e,br),yr=(e,t)=>{const o=e=>{const n=Le(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return C.some(r);const s=o(r);if(s.isSome())return s}return C.none()};return o(e)},xr={scope:["row","col"]},Cr=e=>()=>{const t=xe.fromTag("td",e.dom);return Ie(t,xe.fromTag("br",e.dom)),t},Tr=e=>()=>xe.fromTag("col",e.dom),Sr=e=>()=>xe.fromTag("colgroup",e.dom),Rr=e=>()=>xe.fromTag("tr",e.dom),Dr=(e,t,o)=>{const n=((e,t)=>{const o=Je(e,t),n=Le(Ye(e));return $e(o,n),o})(e,t);return G(o,((e,t)=>{null===e?we(n,t):ge(n,t,e)})),n},Or=e=>e,kr=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;Rt(o)&&Rt(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),_t(t,"height"),1!==e.colspan&&_t(t,"width")};return{col:o=>{const r=xe.fromTag(ne(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:Sr(t),row:Rr(t),cell:r=>{const s=xe.fromTag(ne(r.element),t.dom),l=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),a=l.length>0?((e,t,o)=>wr(e).map((n=>{const r=o.join(","),s=lt(n,r,(t=>Re(t,e)));return z(s,((e,t)=>{const o=Ke(t);return Ie(e,o),o}),t)})).getOr(t))(r.element,s,l):s;return Ie(a,xe.fromTag("br")),n(r,s),((e,t)=>{G(xr,((o,n)=>be(e,n).filter((e=>D(o,e))).each((e=>ge(t,n,e)))))})(r.element,s),e(r.element,s),s},replace:Dr,colGap:Tr(t),gap:Cr(t)}},Er=e=>({col:Tr(e),colgroup:Sr(e),row:Rr(e),cell:Cr(e),replace:Or,colGap:Tr(e),gap:Cr(e)}),Nr=e=>t=>t.options.get(e),Br="100%",_r=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return zo(xe.fromDom(n))+"px"},zr=e=>C.from(e.options.get("table_clone_elements")),Ar=Nr("table_header_type"),Lr=Nr("table_column_resizing"),Wr=e=>"preservetable"===Lr(e),Mr=e=>"resizetable"===Lr(e),jr=Nr("table_sizing_mode"),Pr=e=>"relative"===jr(e),Ir=e=>"fixed"===jr(e),Fr=e=>"responsive"===jr(e),Hr=Nr("table_resize_bars"),$r=Nr("table_style_by_css"),Vr=Nr("table_merge_content_on_paste"),qr=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>Fr(e)||$r(e)?t:Ir(e)?{...t,width:_r(e)}:{...t,width:Br})(e,o)},Ur=Nr("table_use_colgroups"),Gr=e=>ht(e,"[contenteditable]"),Kr=(e,t=!1)=>nt(e)?e.dom.isContentEditable:Gr(e).fold(g(t),(e=>"true"===Yr(e))),Yr=e=>e.dom.contentEditable,Jr=e=>xe.fromDom(e.getBody()),Qr=e=>t=>Re(t,Jr(e)),Xr=e=>{we(e,"data-mce-style");const t=e=>we(e,"data-mce-style");N(Ht(e),t),N($t(e),t),N(qt(e),t)},Zr=e=>xe.fromDom(e.selection.getStart()),es=e=>e.getBoundingClientRect().width,ts=e=>e.getBoundingClientRect().height,os=e=>(t,o)=>{const n=t.dom.getStyle(o,e)||t.dom.getAttrib(o,e);return C.from(n).filter(St)},ns=os("width"),rs=os("height"),ss=e=>dt(e,ue("table")).exists(Kr),ls=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,s=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&s>=e.startRow},as=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,cs=(e,t,o)=>{const n=Xo(e,t,Re),r=Xo(e,o,Re);return n.bind((e=>r.map((t=>{return o=e,n=t,{startRow:Math.min(o.row,n.row),startCol:Math.min(o.column,n.column),finishRow:Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,n.column+n.colspan-1)};var o,n}))))},is=(e,t,o)=>cs(e,t,o).map((t=>{const o=Zo(e,b(ls,t));return E(o,(e=>e.element))})),ms=(e,t)=>Xo(e,t,((e,t)=>De(t,e))).map((e=>e.element)),ds=(e,t,o)=>{const n=fs(e);return is(n,t,o)},us=(e,t,o,n,r)=>{const s=fs(e),l=Re(e,o)?C.some(t):ms(s,t),a=Re(e,r)?C.some(n):ms(s,n);return l.bind((e=>a.bind((t=>is(s,e,t)))))},fs=Yo;var gs=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],hs=()=>({up:g({selector:ut,closest:ht,predicate:mt,all:_e}),down:g({selector:ct,predicate:st}),styles:g({get:Et,getRaw:Bt,set:Ot,remove:_t}),attrs:g({get:pe,set:ge,remove:we,copyTo:(e,t)=>{const o=ve(e);he(t,o)}}),insert:g({before:Me,after:je,afterAll:He,append:Ie,appendAll:$e,prepend:Pe,wrap:Fe}),remove:g({unwrap:Ue,remove:qe}),create:g({nu:xe.fromTag,clone:e=>xe.fromDom(e.dom.cloneNode(!1)),text:xe.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:ze,nextSibling:Ae}),property:g({children:Le,name:ne,parent:Ne,document:e=>Ee(e).dom,isText:ie,isComment:le,isElement:ce,isSpecial:e=>{const t=ne(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>ce(e)?be(e,"lang"):C.none(),getText:ur,setText:gr,isBoundary:e=>!!ce(e)&&("body"===ne(e)||D(gs,ne(e))),isEmptyTag:e=>!!ce(e)&&D(["br","img","hr","input"],ne(e)),isNonEditable:e=>ce(e)&&"false"===pe(e,"contenteditable")}),eq:Re,is:Oe});const ps=(e,t,o,n)=>{const r=t(e,o);return z(n,((o,n)=>{const r=t(e,n);return bs(e,o,r)}),r)},bs=(e,t,o)=>t.bind((t=>o.filter(b(e.eq,t)))),ws=hs(),vs=(e,t)=>((e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,ps):C.none())(ws,((t,o)=>e(o)),t),ys=e=>ut(e,"table"),xs=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Re(t,e);return Re(e,t)?C.some({boxes:C.some([e]),start:e,finish:t}):ys(e).bind((r=>ys(t).bind((s=>{if(Re(r,s))return C.some({boxes:ds(r,e,t),start:e,finish:t});if(De(r,s)){const o=lt(t,"td,th",n(r)),l=o.length>0?o[o.length-1]:t;return C.some({boxes:us(r,e,r,t,s),start:e,finish:l})}if(De(s,r)){const o=lt(e,"td,th",n(s)),l=o.length>0?o[o.length-1]:e;return C.some({boxes:us(s,e,r,t,s),start:e,finish:l})}return((e,t,o)=>((e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),s=[o].concat(e.up().all(o)),l=e=>W(e,n).fold((()=>e),(t=>e.slice(0,t+1))),a=l(r),c=l(s),i=L(a,(t=>O(c,((e,t)=>b(e.eq,t))(e,t))));return{firstpath:a,secondpath:c,shared:i}})(ws,e,t,void 0))(e,t).shared.bind((l=>ht(l,"table",o).bind((o=>{const l=lt(t,"td,th",n(o)),a=l.length>0?l[l.length-1]:t,c=lt(e,"td,th",n(o)),i=c.length>0?c[c.length-1]:e;return C.some({boxes:us(o,e,r,t,s),start:i,finish:a})}))))}))))},Cs=(e,t)=>{const o=ct(e,t);return o.length>0?C.some(o):C.none()},Ts=(e,t,o)=>gt(e,t).bind((t=>gt(e,o).bind((e=>vs(ys,[t,e]).map((o=>({first:t,last:e,table:o}))))))),Ss=(e,t,o,n,r)=>((e,t)=>L(e,(e=>Ce(e,t))))(e,r).bind((e=>((e,t,o)=>Vt(e).bind((n=>((e,t,o,n)=>Xo(e,t,Re).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,s=n>0?t.column+t.colspan-1:t.column;return Qo(e,r+o,s+n).map((e=>e.element))})))(fs(n),e,t,o))))(e,t,o).bind((e=>((e,t)=>ut(e,"table").bind((o=>gt(o,t).bind((t=>xs(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),Rs=(e,t)=>Cs(e,t),Ds=(e,t,o)=>Ts(e,t,o).bind((t=>{const o=t=>Re(e,t),n="thead,tfoot,tbody,table",r=ut(t.first,n,o),s=ut(t.last,n,o);return r.bind((e=>s.bind((o=>Re(e,o)?((e,t,o)=>((e,t,o)=>cs(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=b(as,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let s=t.startCol;s<=t.finishCol;s++)o=o&&Qo(e,r,s).exists(n);return o?C.some(t):C.none()})(e,t))))(fs(e),t,o))(t.table,t.first,t.last):C.none()))))})),Os=h,ks=e=>{const t=(e,t)=>be(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&P(e,(e=>t(e,"rowspan")||t(e,"colspan")))?C.some(e):C.none()},Es=(e,t,o)=>t.length<=1?C.none():Ds(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),Ns="data-mce-selected",Bs="data-mce-first-selected",_s="data-mce-last-selected",zs="["+Ns+"]",As={selected:Ns,selectedSelector:"td["+Ns+"],th["+Ns+"]",firstSelected:Bs,firstSelectedSelector:"td["+Bs+"],th["+Bs+"]",lastSelected:_s,lastSelectedSelector:"td["+_s+"],th["+_s+"]"},Ls=(e,t,o)=>({element:o,mergable:Es(t,e,As),unmergable:ks(e),selection:Os(e)}),Ws=e=>(t,o)=>{const n=ne(t),r="col"===n||"colgroup"===n?Vt(s=t).bind((e=>Rs(e,As.firstSelectedSelector))).fold(g(s),(e=>e[0])):t;var s;return ht(r,e,o)},Ms=Ws("th,td,caption"),js=Ws("th,td"),Ps=e=>{return t=e.model.table.getSelectedCells(),E(t,xe.fromDom);var t},Is=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>Vt(e[0]).map((e=>{const t=((e,t)=>{const o=e=>Ce(e.element,t),n=Ye(e),r=Yt(n),s=ar(e),l=Jo(r),a=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,s=0,l=0;const a=[],c=[];return G(e.access,(e=>{if(a.push(e),t(e)){c.push(e);const t=e.row,o=t+e.rowspan-1,a=e.column,i=a+e.colspan-1;ts&&(s=o),al&&(l=i)}})),((e,t,o,n,r,s)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:s}))(n,r,s,l,a,c)})(l,o),c="th:not("+t+"),td:not("+t+")",i=It(n,"th,td",(e=>Ce(e,c)));N(i,qe),((e,t,o,n)=>{const r=_(e,(e=>"colgroup"!==e.section)),s=t.grid.columns,l=t.grid.rows;for(let e=0;eo.maxRow||ao.maxCol||(Qo(t,e,a).filter(n).isNone()?mr(r,l,e):l=!0)}})(r,l,a,o);const m=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=or(t,e,o),s=A(r,((e,t)=>e+t),0),l=A(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),a=l/s*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(a)})(e,Yo(e),s,a);return((e,t,o,n)=>{G(o.columns,(e=>{(e.columnt.maxCol)&&qe(e.element)}));const r=_(Pt(e,"tr"),(e=>0===e.dom.childElementCount));N(r,qe),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||N(Pt(e,"th,td"),(e=>{we(e,"rowspan"),we(e,"colspan")})),we(e,$o),we(e,"data-snooker-col-series"),ar(e).adjustTableWidth(n)})(n,a,l,m),n})(e,zs);return Xr(t),[t]})))(o).each((o=>{t.content="text"===t.format?(e=>E(e,(e=>e.dom.innerText)).join(""))(o):((e,t)=>E(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o)}))};if(!0===t.selection){const t=(e=>_(Ps(e),(e=>Ce(e,As.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=Ps(e);H(n).each((n=>{Vt(n).each((r=>{const s=_(((e,t)=>{const o=document.createElement("div");return o.innerHTML=e,Le(xe.fromDom(o))})(o.content),(e=>"meta"!==ne(e))),l=ue("table");if(Vr(e)&&1===s.length&&l(s[0])){o.preventDefault();const l=xe.fromDom(e.getDoc()),a=Er(l),c=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,s[0],a);t.pasteCells(r,c).each((()=>{e.focus()}))}}))}))}}))},Fs=(e,t)=>({element:e,offset:t}),Hs=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>Hs(e,t,o).orThunk((()=>C.some(t))))):C.none(),$s=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,Vs=(e,t)=>{const o=Hs(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return Fs(o,$s(e,o));const n=e.property().children(o);return n.length>0?Vs(e,n[n.length-1]):Fs(o,$s(e,o))},qs=Vs,Us=hs(),Gs=(e,t)=>{if(!Lt(e)){const o=(e=>$n(e).bind((e=>{return t=e,o=["fixed","relative","empty"],C.from(_n.exec(t)).bind((e=>{const t=Number(e[1]),n=e[2];return((e,t)=>O(t,(t=>O(Bn[t],(t=>e===t)))))(n,o)?C.some({value:t,unit:n}):C.none()}));var t,o})))(e);o.each((o=>{const n=o.value/2;Gn(e,n,o.unit),Gn(t,n,o.unit)}))}},Ks=e=>E(e,g(0)),Ys=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),Js=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),s=Math.abs(e-t[o]);return n>=0?s:-s}return n},Qs=Js((e=>e<0)),Xs=Js(x),Zs=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,s=Math.max(n,(e[t]+o)/r);return E(e,((e,o)=>(o===t?s:e/r)-e))},t=(t,o,n,r,s,l)=>l?e(t,o,r,s):((e,t,o,n,r)=>{const s=Qs(e,t,n,r);return Ys(e,t,o+1,[s,0],Ks)})(t,o,n,r,s);return{resizeTable:(e,t)=>e(t),clampTableDelta:Qs,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,s,l,a)=>t(e,n,r,s,l,a),calcRightEdgeDeltas:(t,o,n,r,s,l)=>{if(l)return e(t,n,r,s);{const e=Qs(t,n,r,s);return Ks(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=E(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},el=()=>{const e=(e,t,o,n,r)=>{const s=Xs(e,n>=0?o:t,n,r);return Ys(e,t,o+1,[s,-s],Ks)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=A(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return Qs(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,s,l)=>e(t,n,r,s,l),calcRightEdgeDeltas:(e,t,o,n,r,s)=>{if(s)return Ks(e);{const t=n/e.length;return E(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},tl=e=>Yo(e).grid,ol=ue("th"),nl=e=>P(e,(e=>ol(e.element))),rl=(e,t)=>e&&t?"sectionCells":e?"section":"cells",sl=e=>{const t="thead"===e.section,o=pt(ll(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:rl(t,o)}:{type:"body"}},ll=e=>{const t=_(e,(e=>ol(e.element)));return 0===t.length?C.some("td"):t.length===e.length?C.some("th"):C.none()},al=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),cl=(e,t)=>e.section!==t?tt(e.element,e.cells,t,e.isNew):e,il=()=>({transformRow:cl,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==ne(n)?((e,t)=>{const o=Je(e,"td");je(e,o);const n=Le(e);return $e(o,n),qe(e),o})(n):n;return et(r,e.isNew,e.isLocked)}}),ml=()=>({transformRow:cl,transformCell:al}),dl=()=>({transformRow:(e,t)=>cl(e,"thead"===t?"tbody":t),transformCell:al}),ul=il,fl=ml,gl=dl,hl=()=>({transformRow:h,transformCell:al}),pl=(e,t,o,n)=>{o===n?we(e,t):ge(e,t,o)},bl=(e,t,o)=>{$(at(e,t)).fold((()=>Pe(e,o)),(e=>je(e,o)))},wl=(e,t)=>{const o=[],n=[],r=e=>E(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return Ve(t),N(e.cells,(e=>{e.isNew&&n.push(e.element),pl(e.element,"colspan",e.colspan,1),pl(e.element,"rowspan",e.rowspan,1),Ie(t,e.element)})),t})),s=e=>j(e,(e=>E(e.cells,(e=>(pl(e.element,"span",e.colspan,1),e.element))))),l=(t,o)=>{const n=((e,t)=>{const o=ft(e,t).getOrThunk((()=>{const o=xe.fromTag(t,ke(e).dom);return"thead"===t?bl(e,"caption,colgroup",o):"colgroup"===t?bl(e,"caption",o):Ie(e,o),o}));return Ve(o),o})(e,o),l=("colgroup"===o?s:r)(t);$e(n,l)},a=(t,o)=>{t.length>0?l(t,o):(t=>{ft(e,t).each(qe)})(o)},c=[],i=[],m=[],d=[];return N(t,(e=>{switch(e.section){case"thead":c.push(e);break;case"tbody":i.push(e);break;case"tfoot":m.push(e);break;case"colgroup":d.push(e)}})),a(d,"colgroup"),a(c,"thead"),a(i,"tbody"),a(m,"tfoot"),{newRows:o,newCells:n}},vl=(e,t)=>{if(0===e.length)return 0;const o=e[0];return W(e,(e=>!t(o.element,e.element))).getOr(e.length)},yl=(e,t)=>{const o=E(e,(e=>E(e.cells,y)));return E(e,((n,r)=>{const s=j(n.cells,((n,s)=>{if(!1===o[r][s]){const m=((e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),s="colgroup"===r.section,l=vl(r.cells.slice(o),n),a=s?1:vl(((e,t)=>E(e,(e=>jo(e,t))))(e.slice(t),o),n);return{colspan:l,rowspan:a}})(e,r,s,t);return((e,t,n,r)=>{for(let s=e;s({element:e,cells:t,section:o,isNew:n}))(n.element,s,n.section,n.isNew)}))},xl=(e,t,o)=>{const n=[];N(e.colgroups,(r=>{const s=[];for(let n=0;net(e.element,o,!1))).getOrThunk((()=>et(t.colGap(),!0,!1)));s.push(r)}n.push(tt(r.element,s,"colgroup",o))}));for(let r=0;ret(e.element,o,e.isLocked))).getOrThunk((()=>et(t.gap(),!0,!1)));s.push(l)}const l=e.all[r],a=tt(l.element,s,l.section,o);n.push(a)}return n},Cl=e=>yl(e,Re),Tl=(e,t)=>V(e.all,(e=>L(e.cells,(e=>Re(t,e.element))))),Sl=(e,t,o)=>{const n=E(t.selection,(t=>Ft(t).bind((t=>Tl(e,t))).filter(o))),r=bt(n);return wt(r.length>0,r)},Rl=(e,t,o,n,r)=>(s,l,a,c)=>{const i=Yo(s),m=C.from(null==c?void 0:c.section).getOrThunk(hl);return t(i,l).map((t=>{const o=((e,t)=>xl(e,t,!1))(i,a),n=e(o,t,Re,r(a),m),s=qo(n.grid);return{info:t,grid:Cl(n.grid),cursor:n.cursor,lockedColumns:s}})).bind((e=>{const t=wl(s,e.grid),r=C.from(null==c?void 0:c.sizing).getOrThunk((()=>ar(s))),l=C.from(null==c?void 0:c.resize).getOrThunk(el);return o(s,e.grid,e.info,{sizing:r,resize:l,section:m}),n(s),we(s,$o),e.lockedColumns.length>0&&ge(s,$o,e.lockedColumns.join(",")),C.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},Dl=(e,t)=>Sl(e,t,x).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),Ol=(e,t)=>Sl(e,t,x),kl=(e,t)=>Sl(e,t,(e=>!e.isLocked)),El=(e,t)=>P(t,(t=>((e,t)=>Tl(e,t).exists((e=>!e.isLocked)))(e,t))),Nl=(e,t,o,n)=>{const r=Fo(e).rows;let s=!0;for(let e=0;e{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:x,isError:y,map:t=>zl.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>C.some(e)};return r},_l=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:x,map:t,mapError:t=>zl.error(t(e)),bind:t,exists:y,forall:x,getOr:h,or:h,getOrThunk:v,orThunk:v,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:f,toOptional:C.none};var n;return o},zl={value:Bl,error:_l,fromOption:(e,t)=>e.fold((()=>_l(t)),Bl)},Al=(e,t)=>({rowDelta:0,colDelta:Io(e[0])-Io(t[0])}),Ll=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),Wl=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return k(e,(e=>et(r(),!0,n(e))))},Ml=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(k(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=Ho(r,e,h),s=Wl(t.cells.length,t,o,(e=>X(n,e.toString())));return Mo(t,s)})))},jl=(e,t,o,n)=>E(e,(e=>{const r=Wl(t,e,o,y);return Ao(e,n,r)})),Pl=(e,t,o)=>{const n=t.colDelta<0?jl:h,r=t.rowDelta<0?Ml:h,s=qo(e),l=Io(e[0]),a=O(s,(e=>e===l-1)),c=n(e,Math.abs(t.colDelta),o,a?l-1:l),i=qo(c);return r(c,Math.abs(t.rowDelta),o,I(i,x))},Il=(e,t,o,n)=>{const r=b(n,jo(e[t],o).element),s=e[t];return e.length>1&&Io(s)>1&&(o>0&&r(Po(s,o-1))||o0&&r(Po(e[t-1],o))||t_(o,(o=>o>=e.column&&o<=Io(t[0])+e.column)),Hl=(e,t,o,n,r)=>{((e,t,o,n)=>{t>0&&t{const r=e.cells[t-1];let s=0;const l=n();for(;e.cells.length>t+s&&o(r.element,e.cells[t+s].element);)Wo(e,t+s,et(l,!0,e.cells[t+s].isLocked)),s++}))})(t,e,r,n.cell);const s=Ll(o,t),l=Pl(o,s,n),a=Ll(t,l),c=Pl(t,a,n);return E(c,((t,o)=>Ao(t,e,l[o].cells)))},$l=(e,t,o,n,r)=>{((e,t,o,n)=>{const r=Fo(e).rows;if(t>0&&tA(e,((e,o)=>O(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);N(e,(e=>{let s=C.none();for(let l=t;l{Wo(a,t,et(e,!0,c.isLocked))})))}}))}})(t,e,r,n.cell);const s=qo(t),l=Al(t,o),a={...l,colDelta:l.colDelta-s.length},c=Pl(t,a,n),{cols:i,rows:m}=Fo(c),d=qo(c),u=Al(o,t),f={...u,colDelta:u.colDelta+d.length},g=(p=n,b=d,E(o,(e=>A(b,((t,o)=>{const n=Wl(1,e,p,x)[0];return Lo(t,o,n)}),e)))),h=Pl(g,f,n);var p,b;return[...i,...m.slice(0,e),...h,...m.slice(e,m.length)]},Vl=(e,t,o,n,r)=>{const{rows:s,cols:l}=Fo(e),a=s.slice(0,t),c=s.slice(t);return[...l,...a,((e,t,o,n)=>Ho(e,(e=>n(e,o)),t))(s[o],((e,o)=>t>0&&tE(e,(e=>{const s=t>0&&t{if("colgroup"!==o&&n)return jo(e,t);{const t=jo(e,r);return et(l(t.element,s),!0,!1)}})(e,t,e.section,s,o,n,r);return Lo(e,t,l)})),Ul=(e,t,o,n)=>((e,t,o,n)=>void 0!==Po(e[t],o)&&t>0&&n(Po(e[t-1],o),Po(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o(Po(e,t-1),Po(e,t)))(e[t],o,n),Gl=(e,t,o,n)=>{const r=e=>(e=>"row"===e?(e=>At(e,"rowspan")>1)(t):Lt(t))(e)?`${e}group`:e;return e?ol(t)?r(o):null:n&&ol(t)?r("row"===o?"col":"row"):null},Kl=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),Yl=(e,t,o,n,r,s,l)=>E(e,((e,a)=>((e,c)=>{const i=e.cells,m=E(i,((e,c)=>{if((e=>O(t,(t=>o(e.element,t.element))))(e)){const t=l(e,a,c)?r(e,o,n):e;return s(t,a,c).each((e=>{var o,n;o=t.element,n={scope:C.from(e)},G(n,((e,t)=>{e.fold((()=>{we(o,t)}),(e=>{fe(o.dom,t,e)}))}))})),t}return e}));return tt(e.element,m,e.section,e.isNew)})(e))),Jl=(e,t,o)=>j(e,((n,r)=>Ul(e,r,t,o)?[]:[jo(n,t)])),Ql=(e,t,o,n,r)=>{const s=Fo(e).rows,l=j(t,(e=>Jl(s,e,n))),a=E(s,(e=>nl(e.cells))),c=((e,t)=>P(t,h)&&nl(e)?x:(e,o,n)=>!("th"===ne(e.element)&&t[o]))(l,a),i=((e,t)=>(o,n)=>C.some(Gl(e,o.element,"row",t[n])))(o,a);return Yl(e,l,n,r,Kl,i,c)},Xl=(e,t,o,n)=>{const r=Fo(e).rows,s=E(t,(e=>jo(r[e.row],e.column)));return Yl(e,s,o,n,Kl,C.none,x)},Zl=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return N(e,((n,r)=>{const s=q(n);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],c=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(c))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==c.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+c.length+" ("+c+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=q(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!P(t,(e=>D(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o},ea={...Zl([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},ta=(e,t,o)=>{const n=((e,t)=>on(e)?((e,t)=>{const o=tn(e);return E(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=en(e);return E(o,(e=>{const o=((e,t,o)=>{let n=0;for(let r=e;r{o.setElementWidth(e.element,e.width)}))},oa=(e,t,o,n,r)=>{const s=Yo(e),l=r.getCellDelta(t),a=r.getWidths(s,r),c=o===s.grid.columns-1,i=n.clampTableDelta(a,o,l,r.minCellWidth(),c),m=((e,t,o,n,r)=>{const s=e.slice(0),l=((e,t)=>0===e.length?ea.none():1===e.length?ea.only(0):0===t?ea.left(0,1):t===e.length-1?ea.right(t-1,t):t>0&&tn.singleColumnWidth(s[e],o)),((e,t)=>r.calcLeftEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,l)=>r.calcMiddleDeltas(s,e,t,l,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)))})(a,o,i,r,n),d=E(m,((e,t)=>e+a[t]));ta(s,d,r),n.resizeTable(r.adjustTableWidth,i,c)},na=(e,t,o)=>{const n=Yo(e),r=((e,t)=>nr(e,t,Un,(e=>e.getOrThunk(jt))))(n,e),s=E(r,((e,n)=>o===n?Math.max(t+e,jt()):e)),l=((e,t)=>E(e.all,((e,o)=>({element:e.element,height:t[o]}))))(n,s);N(l,(e=>{In(e.element,e.height)})),N(en(n),(e=>{(e=>{_t(e,"height")})(e.element)}));const a=z(s,((e,t)=>e+t),0);In(e,a)},ra=e=>A(e,((e,t)=>O(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),sa=ue("col"),la=ue("colgroup"),aa=e=>"tr"===ne(e)||la(e),ca=e=>({element:e,colspan:zt(e,"colspan",1),rowspan:zt(e,"rowspan",1)}),ia=e=>be(e,"scope").map((e=>e.substr(0,3))),ma=(e,t=ca)=>{const o=o=>{if(aa(o))return la((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,s=(t=>sa(t.element)?e.col(t):e.cell(t))(t(r));return n=C.some({item:r,replacement:s}),s}var r};let n=C.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},da=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},s=t.replace(n,e,r);return o.push({item:n,sub:s}),s};return{replaceOrInit:(e,t)=>{if(aa(e)||sa(e))return e;{const r=e;return((e,t)=>L(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},ua=e=>({unmerge:t=>{const o=ia(t);return o.each((e=>ge(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return _t(n,"width"),_t(t,"width"),o.each((e=>ge(n,"scope",e))),n}},merge:e=>(_t(e[0],"width"),(()=>{const t=bt(E(e,ia));if(0===t.length)return C.none();{const e=t[0],o=["row","col"];return O(t,(t=>t!==e&&D(o,t)))?C.none():C.from(e)}})().fold((()=>we(e[0],"scope")),(t=>ge(e[0],"scope",t+"group"))),g(e[0]))}),fa=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],ga=hs(),ha=e=>((e,t)=>{const o=e.property().name(t);return D(fa,o)})(ga,e),pa=e=>((e,t)=>{const o=e.property().name(t);return D(["ol","ul"],o)})(ga,e),ba=e=>{const t=ue("br"),o=e=>vr(e).bind((o=>{const n=Ae(o).map((e=>!!ha(e)||!!((e,t)=>D(["br","img","hr","input"],e.property().name(t)))(ga,e)&&"img"!==ne(e))).getOr(!1);return Ne(o).map((r=>{return!0===n||("li"===ne(s=r)||mt(s,pa).isSome())||t(o)||ha(r)&&!Re(e,r)?[]:[xe.fromTag("br")];var s}))})).getOr([]),n=(()=>{const n=j(e,(e=>{const n=Le(e);return(e=>P(e,(e=>t(e)||ie(e)&&0===ur(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[xe.fromTag("br")]:n})();Ve(e[0]),$e(e[0],n)},wa=e=>Kr(e,!0),va=e=>{0===Ht(e).length&&qe(e)},ya=(e,t)=>({grid:e,cursor:t}),xa=(e,t,o)=>{const n=((e,t,o)=>{var n,r;const s=Fo(e).rows;return C.from(null===(r=null===(n=s[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(wa).orThunk((()=>(e=>V(e,(e=>V(e.cells,(e=>{const t=e.element;return wt(wa(t),t)})))))(s)))})(e,t,o);return ya(e,n)},Ca=e=>A(e,((e,t)=>O(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),Ta=(e,t)=>(o,n,r,s,l)=>{const a=Ca(n),c=E(a,(e=>e.row)),i=((e,t,o,n,r,s,l)=>{const{cols:a,rows:c}=Fo(e),i=c[t[0]],m=j(t,(e=>((e,t,o)=>{const n=e[t];return j(n.cells,((n,r)=>Ul(e,t,r,o)?[]:[n]))})(c,e,r))),d=E(i.cells,((e,t)=>nl(Jl(c,t,r)))),u=[...c];N(t,(e=>{u[e]=l.transformRow(c[e],o)}));const f=[...a,...u],g=((e,t)=>P(t,h)&&nl(e.cells)?x:(e,o,n)=>!("th"===ne(e.element)&&t[n]))(i,d),p=((e,t)=>(o,n,r)=>C.some(Gl(e,o.element,"col",t[r])))(n,d);return Yl(f,m,r,s,l.transformCell,p,g)})(o,c,e,t,r,s.replaceOrInit,l);return xa(i,n[0].row,n[0].column)},Sa=Ta("thead",!0),Ra=Ta("tbody",!1),Da=Ta("tfoot",!1),Oa=(e,t,o)=>{const n=((e,t)=>Gt(e,(()=>t)))(e,o.section),r=Jo(n);return xl(r,t,!0)},ka=(e,t,o,n)=>((e,t,o,n)=>{const r=Jo(t),s=n.getWidths(r,n);ta(r,s,n)})(0,t,0,n.sizing),Ea=(e,t,o,n)=>((e,t,o,n,r)=>{const s=Jo(t),l=n.getWidths(s,n),a=n.pixelWidth(),{newSizes:c,delta:i}=r.calcRedestributedWidths(l,a,o.pixelDelta,n.isRelative);ta(s,c,n),n.adjustTableWidth(i)})(0,t,o,n.sizing,n.resize),Na=(e,t)=>O(t,(e=>0===e.column&&e.isLocked)),Ba=(e,t)=>O(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),_a=(e,t)=>{const o=rn(e),n=ra(t);return A(n,((e,t)=>e+o[t.column].map(_o).getOr(0)),0)},za=e=>(t,o)=>Ol(t,o).filter((o=>!(e?Na:Ba)(t,o))).map((e=>({details:e,pixelDelta:_a(t,e)}))),Aa=e=>(t,o)=>Dl(t,o).filter((o=>!(e?Na:Ba)(t,o.cells))),La=da("th"),Wa=da("td"),Ma=Rl(((e,t,o,n)=>{const r=t[0].row,s=Ca(t),l=z(s,((e,t)=>({grid:Vl(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return xa(l,r,t[0].column)}),Ol,f,f,ma),ja=Rl(((e,t,o,n)=>{const r=Ca(t),s=r[r.length-1],l=s.row+s.rowspan,a=z(r,((e,t)=>Vl(e,l,t.row,o,n.getOrInit)),e);return xa(a,l,t[0].column)}),Ol,f,f,ma),Pa=Rl(((e,t,o,n)=>{const r=t.details,s=ra(r),l=s[0].column,a=z(s,((e,t)=>({grid:ql(e.grid,l,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return xa(a,r[0].row,l)}),za(!0),Ea,f,ma),Ia=Rl(((e,t,o,n)=>{const r=t.details,s=r[r.length-1],l=s.column+s.colspan,a=ra(r),c=z(a,((e,t)=>ql(e,l,t.column,o,n.getOrInit)),e);return xa(c,r[0].row,l)}),za(!1),Ea,f,ma),Fa=Rl(((e,t,o,n)=>{const r=ra(t.details),s=((e,t)=>j(e,(e=>{const o=e.cells,n=z(t,((e,t)=>t>=0&&t0?[tt(e.element,n,e.section,e.isNew)]:[]})))(e,E(r,(e=>e.column))),l=s.length>0?s[0].cells.length-1:0;return xa(s,r[0].row,Math.min(r[0].column,l))}),((e,t)=>kl(e,t).map((t=>({details:t,pixelDelta:-_a(e,t)})))),Ea,va,ma),Ha=Rl(((e,t,o,n)=>{const r=Ca(t),s=((e,t,o)=>{const{rows:n,cols:r}=Fo(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),l=Math.max(Fo(s).rows.length-1,0);return xa(s,Math.min(t[0].row,l),t[0].column)}),Ol,f,va,ma),$a=Rl(((e,t,o,n)=>{const r=ra(t),s=E(r,(e=>e.column)),l=Ql(e,s,!0,o,n.replaceOrInit);return xa(l,t[0].row,t[0].column)}),kl,f,f,La),Va=Rl(((e,t,o,n)=>{const r=ra(t),s=E(r,(e=>e.column)),l=Ql(e,s,!1,o,n.replaceOrInit);return xa(l,t[0].row,t[0].column)}),kl,f,f,Wa),qa=Rl(Sa,kl,f,f,La),Ua=Rl(Ra,kl,f,f,Wa),Ga=Rl(Da,kl,f,f,Wa),Ka=Rl(((e,t,o,n)=>{const r=Xl(e,t,o,n.replaceOrInit);return xa(r,t[0].row,t[0].column)}),kl,f,f,La),Ya=Rl(((e,t,o,n)=>{const r=Xl(e,t,o,n.replaceOrInit);return xa(r,t[0].row,t[0].column)}),kl,f,f,Wa),Ja=Rl(((e,t,o,n)=>{const r=t.cells;ba(r);const s=((e,t,o,n)=>{const r=Fo(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],s=jo(t,o).isLocked;Wo(t,o,et(n(),!1,s))}return e})(e,t.bounds,0,n.merge(r));return ya(s,C.from(r[0]))}),((e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>El(e,t.cells)))),ka,f,ua),Qa=Rl(((e,t,o,n)=>{const r=z(t,((e,t)=>Nl(e,t,o,n.unmerge(t))),e);return ya(r,C.from(t[0]))}),((e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>El(e,t)))),ka,f,ua),Xa=Rl(((e,t,o,n)=>{const r=((e,t)=>{const o=Yo(e);return xl(o,t,!0)})(t.clipboard,t.generators);var s,l;return((e,t,o,n,r)=>{const s=qo(t),l=((e,t,o)=>{const n=Io(t[0]),r=Fo(t).cols.length+e.row,s=k(n-e.column,(t=>t+e.column));return{row:r,column:L(s,(e=>P(o,(t=>t!==e)))).getOr(n-1)}})(e,t,s),a=Fo(o).rows,c=Fl(l,a,s),i=((e,t,o)=>{if(e.row>=t.length||e.column>Io(t[0]))return zl.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),s=Io(o[0]),l=o.length;return zl.value({rowDelta:n.length-l,colDelta:r.length-s})})(l,t,a);return i.map((e=>{const o={...e,colDelta:e.colDelta-c.length},s=Pl(t,o,n),i=qo(s),m=Fl(l,a,i);return((e,t,o,n,r,s)=>{const l=e.row,a=e.column,c=l+o.length,i=a+Io(o[0])+s.length,m=I(s,x);for(let e=l;eya(e,C.some(t.element))),(e=>xa(e,t.row,t.column)))}),((e,t)=>Ft(t.element).bind((o=>Tl(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard})))))),ka,f,ma),Za=Rl(((e,t,o,n)=>{const r=Fo(e).rows,s=t.cells[0].column,l=r[t.cells[0].row],a=Oa(t.clipboard,t.generators,l),c=Hl(s,e,a,t.generators,o);return xa(c,t.cells[0].row,t.cells[0].column)}),Aa(!0),f,f,ma),ec=Rl(((e,t,o,n)=>{const r=Fo(e).rows,s=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,l=r[t.cells[0].row],a=Oa(t.clipboard,t.generators,l),c=Hl(s,e,a,t.generators,o);return xa(c,t.cells[0].row,s)}),Aa(!1),f,f,ma),tc=Rl(((e,t,o,n)=>{const r=Fo(e).rows,s=t.cells[0].row,l=r[s],a=Oa(t.clipboard,t.generators,l),c=$l(s,e,a,t.generators,o);return xa(c,t.cells[0].row,t.cells[0].column)}),Dl,f,f,ma),oc=Rl(((e,t,o,n)=>{const r=Fo(e).rows,s=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,l=r[t.cells[0].row],a=Oa(t.clipboard,t.generators,l),c=$l(s,e,a,t.generators,o);return xa(c,s,t.cells[0].column)}),Dl,f,f,ma),nc=(e,t)=>{const o=Yo(e);return Ol(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=M(E(o.all,(e=>_(e.cells,(e=>e.column>=n&&e.column{const o=Yo(e);return Ol(o,t).bind(ll).getOr("")},sc=(e,t)=>{const o=Yo(e);return Ol(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=E(e,(e=>sl(e).type)),o=D(t,"header"),n=D(t,"footer");if(o||n){const e=D(t,"body");return!o||e||n?o||e||!n?C.none():C.some("footer"):C.some("header")}return C.some("body")})(o.all.slice(n,r))})).getOr("")},lc=(e,t)=>e.dispatch("NewRow",{node:t}),ac=(e,t)=>e.dispatch("NewCell",{node:t}),cc=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},ic={structure:!1,style:!0},mc={structure:!0,style:!1},dc={structure:!0,style:!0},uc=(e,t)=>Pr(e)?ir(t):Ir(e)?cr(t):ar(t),fc=(e,t,o)=>{const n=e=>"table"===ne(Jr(e)),r=zr(e),s=Mr(e)?f:Gs,l=t=>{switch(Ar(e)){case"section":return ul();case"sectionCells":return fl();case"cells":return gl();default:return((e,t)=>{var o;switch((o=Yo(e),V(o.all,(e=>{const t=sl(e);return"header"===t.type?C.from(t.subType):C.none()}))).getOr(t)){case"section":return il();case"sectionCells":return ml();case"cells":return dl()}})(t,"section")}},a=(n,s,a,c)=>(i,m,d=!1)=>{Xr(i);const u=xe.fromDom(e.getDoc()),f=kr(a,u,r),g={sizing:uc(e,i),resize:Mr(e)?Zs():el(),section:l(i)};return s(i)?n(i,m,f,g).bind((n=>{t.refresh(i.dom),N(n.newRows,(t=>{lc(e,t.dom)})),N(n.newCells,(t=>{ac(e,t.dom)}));const r=((t,n)=>n.cursor.fold((()=>{const n=Ht(t);return H(n).filter(nt).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),ge(n,"data-mce-selected","1"),r}))}),(n=>{const r=qs(Us,n),s=e.dom.createRng();return s.setStart(r.element.dom,r.offset),s.setEnd(r.element.dom,r.offset),e.selection.setRng(s),o.clearSelectedCells(t.dom),C.some(s)})))(i,n);return nt(i)&&(Xr(i),d||cc(e,i.dom,c)),r.map((e=>({rng:e,effect:c})))})):C.none()},c=a(Ha,(t=>!n(e)||tl(t).rows>1),f,mc),i=a(Fa,(t=>!n(e)||tl(t).columns>1),f,mc);return{deleteRow:c,deleteColumn:i,insertRowsBefore:a(Ma,x,f,mc),insertRowsAfter:a(ja,x,f,mc),insertColumnsBefore:a(Pa,x,s,mc),insertColumnsAfter:a(Ia,x,s,mc),mergeCells:a(Ja,x,f,mc),unmergeCells:a(Qa,x,f,mc),pasteColsBefore:a(Za,x,f,mc),pasteColsAfter:a(ec,x,f,mc),pasteRowsBefore:a(tc,x,f,mc),pasteRowsAfter:a(oc,x,f,mc),pasteCells:a(Xa,x,f,dc),makeCellsHeader:a(Ka,x,f,mc),unmakeCellsHeader:a(Ya,x,f,mc),makeColumnsHeader:a($a,x,f,mc),unmakeColumnsHeader:a(Va,x,f,mc),makeRowsHeader:a(qa,x,f,mc),makeRowsBody:a(Ua,x,f,mc),makeRowsFooter:a(Ga,x,f,mc),getTableRowType:sc,getTableCellType:rc,getTableColType:nc}},gc=(e,t,o)=>{const n=zt(e,t,1);1===o||n<=1?we(e,t):ge(e,t,Math.min(o,n))},hc=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):pc.invalid(o)},wc={...pc,from:e=>Ct(e,"%")?bc("%",pc.percent,e):Ct(e,"px")?bc("px",pc.pixels,e):pc.invalid(e)},vc=(e,t,o)=>{const n=wc.from(o),r=P(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return k(t,o)})(n,e.length):((e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return E(e,(e=>wc.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>E(e,(e=>wc.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))))(n,e,t);return Cc(r)},yc=(e,t)=>0===e.length?t:z(e,((e,t)=>wc.from(t).fold(g(0),h,h)+e),0),xc=(e,t)=>wc.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),Cc=e=>{if(0===e.length)return e;const t=z(e,((e,t)=>{const o=wc.from(t).fold((()=>({value:t,remainder:0})),(e=>((e,t)=>{const o=Math.floor(e);return{value:o+"px",remainder:e-o}})(e)),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([xc(o[o.length-1],Math.round(t.remainder))])},Tc=wc.from,Sc=(e,t,o)=>{const n=Yo(e),r=n.all,s=en(n),l=tn(n);t.each((t=>{const o=Tc(t).fold(g("px"),g("px"),g("%")),r=Bo(e),a=((e,t)=>er(e,t,Qn,tr))(n,e),c=vc(a,r,t);on(n)?((e,t,o)=>{N(t,((t,n)=>{const r=yc([e[n]],Mt());Ot(t.element,"width",r+o)}))})(c,l,o):((e,t,o)=>{N(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=yc(n,Mt());Ot(t.element,"width",r+o)}))})(c,s,o),Ot(e,"width",t)})),o.each((t=>{const o=dn(e),l=((e,t)=>nr(e,t,Xn,tr))(n,e);((e,t,o)=>{N(o,(e=>{_t(e.element,"height")})),N(t,((t,o)=>{Ot(t.element,"height",e[o])}))})(vc(l,o,t),r,s),Ot(e,"height",t)}))},Rc=e=>$n(e).exists((e=>zn.test(e))),Dc=e=>$n(e).exists((e=>An.test(e))),Oc=e=>$n(e).isNone(),kc=e=>{we(e,"width"),we(e,"height")},Ec=e=>{const t=Kn(e);Sc(e,C.some(t),C.none()),kc(e)},Nc=e=>{const t=(e=>Bo(e)+"px")(e);Sc(e,C.some(t),C.none()),kc(e)},Bc=e=>{_t(e,"width");const t=$t(e),o=t.length>0?t:Ht(e);N(o,(e=>{_t(e,"width"),kc(e)})),kc(e)},_c={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},zc=(e,t,o,n)=>k(e,(e=>((e,t,o,n)=>{const r=xe.fromTag("tr");for(let s=0;s{e.selection.select(t.dom,!0),e.selection.collapse(!0)},Lc=(e,t,o,n,s)=>{const l=(e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>Fr(e)||!$r(e)?t:Ir(e)?{...t,width:_r(e)}:{...t,width:Br})(e,o)})(e),a={styles:l,attributes:qr(e),colGroups:Ur(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,s=_c)=>{const l=xe.fromTag("table"),a="cells"!==r;kt(l,s.styles),he(l,s.attributes),s.colGroups&&Ie(l,(e=>{const t=xe.fromTag("colgroup");return k(e,(()=>Ie(t,xe.fromTag("col")))),t})(t));const c=Math.min(e,o);if(a&&o>0){const e=xe.fromTag("thead");Ie(l,e);const s=zc(o,t,"sectionCells"===r?c:0,n);$e(e,s)}const i=xe.fromTag("tbody");Ie(l,i);const m=zc(a?e-c:e,t,a?0:o,n);return $e(i,m),l})(o,t,s,n,Ar(e),a);ge(r,"data-mce-id","__mce");const l=(e=>{const t=xe.fromTag("div"),o=xe.fromDom(e.dom.cloneNode(!0));return Ie(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(l),e.addVisual()})),gt(Jr(e),'table[data-mce-id="__mce"]').map((t=>(Ir(e)?Nc(t):Fr(e)?Bc(t):(Pr(e)||(e=>r(e)&&-1!==e.indexOf("%"))(l.width))&&Ec(t),Xr(t),we(t,"data-mce-id"),((e,t)=>{N(ct(t,"tr"),(t=>{lc(e,t.dom),N(ct(t,"th,td"),(t=>{ac(e,t.dom)}))}))})(e,t),((e,t)=>{gt(t,"td,th").each(b(Ac,e))})(e,t),t.dom))).getOrNull()};var Wc=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const Mc="x-tinymce/dom-table-",jc=Mc+"rows",Pc=Mc+"columns",Ic=e=>{const t=Wc.FakeClipboardItem(e);Wc.write([t])},Fc=e=>{var t;const o=null!==(t=Wc.read())&&void 0!==t?t:[];return V(o,(t=>C.from(t.getType(e))))},Hc=e=>{Fc(e).isSome()&&Wc.clear()},$c=e=>{e.fold(qc,(e=>Ic({[jc]:e})))},Vc=()=>Fc(jc),qc=()=>Hc(jc),Uc=e=>{e.fold(Kc,(e=>Ic({[Pc]:e})))},Gc=()=>Fc(Pc),Kc=()=>Hc(Pc),Yc=e=>Ms(Zr(e),Qr(e)).filter(ss),Jc=(e,t)=>{const o=Qr(e),n=e=>Vt(e,o),l=t=>(e=>js(Zr(e),Qr(e)).filter(ss))(e).bind((e=>n(e).map((o=>t(o,e))))),a=t=>{e.focus()},c=(t,o=!1)=>l(((n,r)=>{const s=Ls(Ps(e),n,r);t(n,s,o).each(a)})),i=()=>l(((t,o)=>((e,t,o)=>{const n=Yo(e);return Ol(n,t).bind((e=>{const t=xl(n,o,!1),r=Fo(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),s=j(r,(e=>{const t=_(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),l=Cl(s);return wt(l.length>0,l)})).map((e=>E(e,(e=>{const t=Ke(e.element);return N(e.cells,(e=>{const o=Ye(e.element);pl(o,"colspan",e.colspan,1),pl(o,"rowspan",e.rowspan,1),Ie(t,o)})),t}))))})(t,Ls(Ps(e),t,o),kr(f,xe.fromDom(e.getDoc()),C.none())))),m=()=>l(((t,o)=>((e,t)=>{const o=Yo(e);return kl(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=((e,t,o)=>{if(on(e)){const n=_(tn(e),hc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return gc(n,"span",o-t),n})),s=xe.fromTag("colgroup");return $e(s,r),[s]}return[]})(o,n,r),l=((e,t,o)=>E(e.all,(e=>{const n=_(e.cells,hc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return gc(n,"colspan",o-t),n})),s=xe.fromTag("tr");return $e(s,r),s})))(o,n,r);return[...s,...l]}))})(t,Ls(Ps(e),t,o)))),d=(t,o)=>o().each((o=>{const n=E(o,(e=>Ye(e)));l(((o,r)=>{const s=Er(xe.fromDom(e.getDoc())),l=((e,t,o,n)=>({selection:Os(e),clipboard:o,generators:n}))(Ps(e),0,n,s);t(o,l).each(a)}))})),g=e=>(t,o)=>((e,t)=>X(e,t)?C.from(e[t]):C.none())(o,"type").each((t=>{c(e(t),o.no_events)}));G({mceTableSplitCells:()=>c(t.unmergeCells),mceTableMergeCells:()=>c(t.mergeCells),mceTableInsertRowBefore:()=>c(t.insertRowsBefore),mceTableInsertRowAfter:()=>c(t.insertRowsAfter),mceTableInsertColBefore:()=>c(t.insertColumnsBefore),mceTableInsertColAfter:()=>c(t.insertColumnsAfter),mceTableDeleteCol:()=>c(t.deleteColumn),mceTableDeleteRow:()=>c(t.deleteRow),mceTableCutCol:()=>m().each((e=>{Uc(e),c(t.deleteColumn)})),mceTableCutRow:()=>i().each((e=>{$c(e),c(t.deleteRow)})),mceTableCopyCol:()=>m().each((e=>Uc(e))),mceTableCopyRow:()=>i().each((e=>$c(e))),mceTablePasteColBefore:()=>d(t.pasteColsBefore,Gc),mceTablePasteColAfter:()=>d(t.pasteColsAfter,Gc),mceTablePasteRowBefore:()=>d(t.pasteRowsBefore,Vc),mceTablePasteRowAfter:()=>d(t.pasteRowsAfter,Vc),mceTableDelete:()=>Yc(e).each((t=>{Vt(t,o).filter(w(o)).each((t=>{const o=xe.fromText("");if(je(t,o),qe(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{l((t=>{const n=Ps(e),r=P(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),s=r?e.formatter.remove:e.formatter.apply;N(n,(e=>s("tablecellclass",{value:o},e.dom))),cc(e,t.dom,ic)}))},mceTableToggleClass:(t,o)=>{l((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),cc(e,t.dom,ic)}))},mceTableToggleCaption:()=>{Yc(e).each((t=>{Vt(t,o).each((o=>{ft(o,"caption").fold((()=>{const t=xe.fromTag("caption");Ie(t,xe.fromText("Caption")),((e,t,o)=>{We(e,0).fold((()=>{Ie(e,t)}),(e=>{Me(e,t)}))})(o,t),e.selection.setCursorLocation(t.dom,0)}),(n=>{ue("caption")(t)&&Se("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),qe(n)})),cc(e,o.dom,mc)}))}))},mceTableSizingMode:(t,n)=>(t=>Yc(e).each((n=>{Fr(e)||Ir(e)||Pr(e)||Vt(n,o).each((o=>{"relative"!==t||Rc(o)?"fixed"!==t||Dc(o)?"responsive"!==t||Oc(o)||Bc(o):Nc(o):Ec(o),Xr(o),cc(e,o.dom,mc)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>u(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,s=n.headerColumns||0;return Lc(e,o,t,s,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const l=e=>"tablecell"+e.toLowerCase().replace("-","");if(!s(o))return;const a=_(Ps(e),ss);if(0===a.length)return;const c=((e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),f),o})(o,((t,o)=>e.formatter.has(l(o))&&r(t)));(e=>{for(const t in e)if(U.call(e,t))return!1;return!0})(c)||(G(c,((t,o)=>{const n=l(o);N(a,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(a[0]).each((t=>cc(e,t.dom,ic))))}))},Qc=Zl([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),Xc={before:Qc.before,on:Qc.on,after:Qc.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(h,h,h)},Zc=(e,t)=>({selection:e,kill:t}),ei=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},ti=(e,t)=>{const o=e.document.createRange();return oi(o,t),o},oi=(e,t)=>e.selectNodeContents(t.dom),ni=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},ri=(e,t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},si=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),li=Zl([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),ai=(e,t,o)=>t(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset),ci=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:C.none}),relative:(t,o)=>({ltr:Jt((()=>ni(e,t,o))),rtl:Jt((()=>C.some(ni(e,o,t))))}),exact:(t,o,n,r)=>({ltr:Jt((()=>ri(e,t,o,n,r))),rtl:Jt((()=>C.some(ri(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>li.rtl(xe.fromDom(e.endContainer),e.endOffset,xe.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>ai(0,li.ltr,o))):ai(0,li.ltr,o)})(0,o)},ii=(e,t)=>ci(e,t).match({ltr:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},rtl:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(n.dom,r),s.setEnd(t.dom,o),s}});li.ltr,li.rtl;const mi=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),di=(e,t,o,n)=>({start:Xc.on(e,t),finish:Xc.on(o,n)}),ui=(e,t)=>{const o=ii(e,t);return mi(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset)},fi=di,gi=(e,t,o,n,r)=>Re(o,n)?C.none():xs(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),C.some(Zc(C.some(fi(o,0,o,hr(o))),!0))):C.none()})),hi=(e,t)=>({item:e,mode:t}),pi=(e,t,o,n=bi)=>e.property().parent(t).map((e=>hi(e,n))),bi=(e,t,o,n=wi)=>o.sibling(e,t).map((e=>hi(e,n))),wi=(e,t,o,n=wi)=>{const r=e.property().children(t);return o.first(r).map((e=>hi(e,n)))},vi=[{current:pi,next:bi,fallback:C.none()},{current:bi,next:wi,fallback:C.some(pi)},{current:wi,next:wi,fallback:C.some(bi)}],yi=(e,t,o,n,r=vi)=>L(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>yi(e,t,o,n))))))),xi=(e,t,o,n,r,s)=>yi(e,t,n,r).bind((t=>s(t.item)?C.none():o(t.item)?C.some(t.item):xi(e,t.item,o,t.mode,r,s))),Ci=e=>t=>0===e.property().children(t).length,Ti=(e,t,o,n)=>xi(e,t,o,bi,{sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?C.some(e[e.length-1]):C.none()},n),Si=(e,t,o,n)=>xi(e,t,o,bi,{sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?C.some(e[0]):C.none()},n),Ri=hs(),Di=(e,t)=>((e,t,o)=>Ti(e,t,Ci(e),o))(Ri,e,t),Oi=(e,t)=>((e,t,o)=>Si(e,t,Ci(e),o))(Ri,e,t),ki=Zl([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),Ei=e=>ht(e,"tr"),Ni={...ki,verify:(e,t,o,n,r,s,l)=>ht(n,"td,th",l).bind((o=>ht(t,"td,th",l).map((t=>Re(o,t)?Re(n,o)&&hr(o)===r?s(t):ki.none("in same cell"):vs(Ei,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.lefts(t))))))).getOr(ki.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},Bi=ue("br"),_i=(e,t,o)=>t(e,o).bind((e=>ie(e)&&0===ur(e).trim().length?_i(e,t,o):C.some(e))),zi=(e,t,o,n)=>((e,t)=>We(e,t).filter(Bi).orThunk((()=>We(e,t-1).filter(Bi))))(t,o).bind((t=>n.traverse(t).fold((()=>_i(t,n.gather,e).map(n.relative)),(e=>(e=>Ne(e).bind((t=>{const o=Le(t);return((e,t)=>W(e,b(Re,t)))(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>Xc.on(e.parent,e.index))))))),Ai=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),Li=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),Wi=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),Mi=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),ji=(e,t)=>C.some(e.getRect(t)),Pi=(e,t,o)=>ce(t)?ji(e,t).map(Mi):ie(t)?((e,t,o)=>o>=0&&o0?e.getRangedRect(t,o-1,t,o):C.none())(e,t,o).map(Mi):C.none(),Ii=(e,t)=>ce(t)?ji(e,t).map(Mi):ie(t)?e.getRangedRect(t,0,t,hr(t)).map(Mi):C.none(),Fi=Zl([{none:[]},{retry:["caret"]}]),Hi=(e,t,o)=>dt(t,ha).fold(y,(t=>Ii(e,t).exists((e=>((e,t)=>e.leftt.right)(o,e))))),$i={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const s=Ai(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?Fi.retry(s):o.top===r.bottom?Fi.retry(Ai(r,1)):Hi(e,t,r)?Fi.retry(Wi(s,5,0)):Fi.none()},move:Ai,gather:Oi},Vi=(e,t,o,n,r)=>0===r?C.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===ne(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Vi(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((s=>s.start.fold(C.none,(s=>Ii(e,s).bind((l=>t.adjuster(e,s,l,o,n).fold(C.none,(n=>Vi(e,t,o,n,r-1))))).orThunk((()=>C.some(n)))),C.none))),qi=(e,t,o)=>{const n=e.move(o,5),r=Vi(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?C.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?C.some(-e.point(t)):C.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},Ui={tryUp:b(qi,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const s=Li(r,5);return Math.abs(o.top-n.top)<1||o.bottome.getSelection().bind((n=>((e,t,o,n)=>{const r=Bi(t)?((e,t,o)=>o.traverse(t).orThunk((()=>_i(t,o.gather,e))).map(o.relative))(e,t,n):zi(e,t,o,n);return r.map((e=>({start:e,finish:e})))})(t,n.finish,n.foffset,o).fold((()=>C.some(Fs(n.finish,n.foffset))),(r=>{const s=e.fromSitus(r);return l=Ni.verify(e,n.finish,n.foffset,s.finish,s.foffset,o.failure,t),Ni.cata(l,(e=>C.none()),(()=>C.none()),(e=>C.some(Fs(e,0))),(e=>C.some(Fs(e,hr(e)))));var l})))),Ki=(e,t,o,n,r,s)=>0===s?C.none():Qi(e,t,o,n,r).bind((l=>{const a=e.fromSitus(l),c=Ni.verify(e,o,n,a.finish,a.foffset,r.failure,t);return Ni.cata(c,(()=>C.none()),(()=>C.some(l)),(l=>Re(o,l)&&0===n?Yi(e,o,n,Li,r):Ki(e,t,l,0,r,s-1)),(l=>Re(o,l)&&n===hr(l)?Yi(e,o,n,Ai,r):Ki(e,t,l,hr(l),r,s-1)))})),Yi=(e,t,o,n,r)=>Pi(e,t,o).bind((t=>Ji(e,r,n(t,Ui.getJumpSize())))),Ji=(e,t,o)=>{const n=Oo().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):C.none()},Qi=(e,t,o,n,r)=>Pi(e,o,n).bind((t=>Ji(e,r,t))),Xi=(e,t,o,n,r)=>ht(n,"td,th",t).bind((n=>ht(n,"table",t).bind((s=>((e,t)=>mt(e,(e=>Ne(e).exists((e=>Re(e,t)))),void 0).isSome())(r,s)?((e,t,o)=>Gi(e,t,o).bind((n=>Ki(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>ht(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):C.none())))),Zi=(e,t,o,n,r,s)=>s(n,t).orThunk((()=>Xi(e,t,o,n,r).map((e=>{const t=e.range;return Zc(C.some(fi(t.start,t.soffset,t.finish,t.foffset)),!0)})))),em=(e,t)=>ht(e,"tr",t).bind((e=>ht(e,"table",t).bind((o=>{const n=ct(o,"tr");return Re(e,n[0])?((e,t,o)=>Ti(Ri,e,(e=>vr(e).isSome()),o))(o,0,t).map((e=>{const t=hr(e);return Zc(C.some(fi(e,t,e,t)),!0)})):C.none()})))),tm=(e,t)=>ht(e,"tr",t).bind((e=>ht(e,"table",t).bind((o=>{const n=ct(o,"tr");return Re(e,n[n.length-1])?((e,t,o)=>Si(Ri,e,(e=>wr(e).isSome()),o))(o,0,t).map((e=>Zc(C.some(fi(e,0,e,0)),!0))):C.none()})))),om=(e,t,o,n,r,s,l)=>Xi(e,o,n,r,s).bind((e=>gi(t,o,e.start,e.finish,l))),nm=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},rm=()=>{const e=(e=>{const t=nm(C.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(C.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(C.some(e))}}})(f);return{...e,on:t=>e.get().each(t)}},sm=(e,t)=>ht(e,"td,th",t),lm=e=>Be(e).exists(Kr),am={traverse:Ae,gather:Oi,relative:Xc.before,retry:Ui.tryDown,failure:Ni.failedDown},cm={traverse:ze,gather:Di,relative:Xc.before,retry:Ui.tryUp,failure:Ni.failedUp},im=e=>t=>t===e,mm=im(38),dm=im(40),um=e=>e>=37&&e<=40,fm={isBackward:im(37),isForward:im(39)},gm={isBackward:im(39),isForward:im(37)},hm=Zl([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),pm={domRange:hm.domRange,relative:hm.relative,exact:hm.exact,exactFromRange:e=>hm.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>xe.fromDom(e.startContainer),relative:(e,t)=>Xc.getStart(e),exact:(e,t,o,n)=>e}))(e);return xe.fromDom(Ee(t).dom.defaultView)},range:mi},bm=(e,t)=>{const o=ne(e);return"input"===o?Xc.after(e):D(["br","img"],o)?0===t?Xc.before(e):Xc.after(e):Xc.on(e,t)},wm=e=>C.from(e.getSelection()),vm=(e,t)=>{wm(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},ym=(e,t,o,n,r)=>{const s=ri(e,t,o,n,r);vm(e,s)},xm=(e,t)=>ci(e,t).match({ltr:(t,o,n,r)=>{ym(e,t,o,n,r)},rtl:(t,o,n,r)=>{wm(e).each((s=>{if(s.setBaseAndExtent)s.setBaseAndExtent(t.dom,o,n.dom,r);else if(s.extend)try{((e,t,o,n,r,s)=>{t.collapse(o.dom,n),t.extend(r.dom,s)})(0,s,t,o,n,r)}catch(s){ym(e,n,r,t,o)}else ym(e,n,r,t,o)}))}}),Cm=(e,t,o,n,r)=>{const s=((e,t,o,n)=>{const r=bm(e,t),s=bm(o,n);return pm.relative(r,s)})(t,o,n,r);xm(e,s)},Tm=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(Xc.before,bm,Xc.after),n=t.fold(Xc.before,bm,Xc.after);return pm.relative(o,n)})(t,o);xm(e,n)},Sm=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return C.some(mi(xe.fromDom(t.startContainer),t.startOffset,xe.fromDom(o.endContainer),o.endOffset))}return C.none()},Rm=e=>{if(null===e.anchorNode||null===e.focusNode)return Sm(e);{const t=xe.fromDom(e.anchorNode),o=xe.fromDom(e.focusNode);return((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=ke(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),s=Re(e,o)&&t===n;return r.collapsed&&!s})(t,e.anchorOffset,o,e.focusOffset)?C.some(mi(t,e.anchorOffset,o,e.focusOffset)):Sm(e)}},Dm=(e,t,o=!0)=>{const n=(o?ti:ei)(e,t);vm(e,n)},Om=e=>(e=>wm(e).filter((e=>e.rangeCount>0)).bind(Rm))(e).map((e=>pm.exact(e.start,e.soffset,e.finish,e.foffset))),km=(e,t,o)=>((e,t,o)=>((e,t,o)=>e.caretPositionFromPoint?((e,t,o)=>{var n;return C.from(null===(n=e.caretPositionFromPoint)||void 0===n?void 0:n.call(e,t,o)).bind((t=>{if(null===t.offsetNode)return C.none();const o=e.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),C.some(o)}))})(e,t,o):e.caretRangeFromPoint?((e,t,o)=>{var n;return C.from(null===(n=e.caretRangeFromPoint)||void 0===n?void 0:n.call(e,t,o))})(e,t,o):C.none())(e.document,t,o).map((e=>mi(xe.fromDom(e.startContainer),e.startOffset,xe.fromDom(e.endContainer),e.endOffset))))(e,t,o),Em=e=>({elementFromPoint:(t,o)=>xe.fromPoint(xe.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const s=pm.exact(t,o,n,r);return((e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?C.some(o).map(si):C.none()})(ii(e,t)))(e,s)},getSelection:()=>Om(e).map((t=>ui(e,t))),fromSitus:t=>{const o=pm.relative(t.start,t.finish);return ui(e,o)},situsFromPoint:(t,o)=>km(e,t,o).map((e=>di(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{wm(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{Om(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;Tm(e,r,r)}),((o,n,r,s)=>{const l=t?o:r,a=t?n:s;Cm(e,l,a,l,a)}))))},setSelection:t=>{Cm(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{Tm(e,t,o)},selectNode:t=>{Dm(e,t,!1)},selectContents:t=>{Dm(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return gn(o,n)})(xe.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,xe.fromDom(e.document))}}),Nm=(e,t)=>({rows:e,cols:t}),Bm=e=>dt(e,ae).exists(Kr),_m=(e,t)=>Bm(e)||Bm(t),zm=e=>void 0!==e.dom.classList,Am=(e,t)=>((e,t,o)=>{const n=((e,t)=>{const o=pe(e,t);return void 0===o||""===o?[]:o.split(" ")})(e,t).concat([o]);return ge(e,t,n.join(" ")),!0})(e,"class",t),Lm=(e,t)=>{zm(e)?e.dom.classList.add(t):Am(e,t)},Wm=(e,t)=>zm(e)&&e.dom.classList.contains(t),Mm=()=>({tag:"none"}),jm=e=>({tag:"multiple",elements:e}),Pm=e=>({tag:"single",element:e}),Im=e=>{const t=xe.fromDom((e=>{if(m(e.target)){const t=xe.fromDom(e.target);if(ce(t)&&m(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return H(t)}}return C.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(s=n,l=o,(...e)=>s(l.apply(null,e)));var s,l;return((e,t,o,n,r,s,l)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:s,raw:l}))(t,e.clientX,e.clientY,o,n,r,e)},Fm=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},Hm=x,$m=(e,t,o)=>((e,t,o,n)=>((e,t,o,n,r)=>{const s=((e,t)=>o=>{e(o)&&t(Im(o))})(o,n);return e.dom.addEventListener(t,s,r),{unbind:b(Fm,e,t,s,r)}})(e,t,o,n,!1))(e,t,Hm,o),Vm=Im,qm=e=>!Wm(xe.fromDom(e.target),"ephox-snooker-resizer-bar"),Um=(e,t)=>{const o=(r=As.selectedSelector,{get:()=>Rs(xe.fromDom(e.getBody()),r).fold((()=>js(Zr(e),Qr(e)).fold(Mm,Pm)),jm)}),n=((e,t,o)=>{const n=t=>{we(t,e.selected),we(t,e.firstSelected),we(t,e.lastSelected)},r=t=>{ge(t,e.selected,"1")},s=e=>{l(e),o()},l=t=>{const o=ct(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);N(o,n)};return{clearBeforeUpdate:l,clear:s,selectRange:(o,n,l,a)=>{s(o),N(n,r),ge(l,e.firstSelected,"1"),ge(a,e.lastSelected,"1"),t(n,l,a)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}})(As,((t,o,n)=>{Vt(o).each((r=>{const s=E(t,(e=>e.dom)),l=zr(e),a=kr(f,xe.fromDom(e.getDoc()),l),c=((e,t,o)=>{const n=Yo(e);return Ol(n,t).map((e=>{const t=xl(n,o,!1),{rows:r}=Fo(t),s=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=Cl(o);return j(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return E(o,(e=>e.element))}))})(r,e),l=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=Cl(o);return j(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return E(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:s,downOrRightCells:l}}))})(r,{selection:Ps(e)},a).map((e=>K(e,(e=>E(e,(e=>e.dom)))))).getOrUndefined();((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,s,o.dom,n.dom,c)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));var r;return e.on("init",(o=>{const r=e.getWin(),s=Jr(e),l=Qr(e),a=((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=rm(),s=r.clear,l=s=>{r.on((r=>{n.clearBeforeUpdate(t),sm(s.target,o).each((l=>{xs(r,l,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const e=r[0],o="false"===Yr(e),l=pt(Gr(s.target),e,Re);o&&l&&n.selectRange(t,r,e,e)}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(l))}))}))}))};return{clearstate:s,mousedown:e=>{n.clear(t),sm(e.target,o).filter(lm).each(r.set)},mouseover:e=>{l(e)},mouseup:e=>{l(e),s()}}})(Em(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}})(r,s,l,n),c=((e,t,o,n)=>{const r=Em(e),s=()=>(n.clear(t),C.none());return{keydown:(e,l,a,c,i,m)=>{const d=e.raw,u=d.which,f=!0===d.shiftKey,g=Cs(t,n.selectedSelector).fold((()=>(um(u)&&!f&&n.clearBeforeUpdate(t),um(u)&&f&&!_m(l,c)?C.none:dm(u)&&f?b(om,r,t,o,am,c,l,n.selectRange):mm(u)&&f?b(om,r,t,o,cm,c,l,n.selectRange):dm(u)?b(Zi,r,o,am,c,l,tm):mm(u)?b(Zi,r,o,cm,c,l,em):C.none)),(e=>{const o=o=>()=>{const s=V(o,(o=>((e,t,o,n,r)=>Ss(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return s.fold((()=>Ts(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=dm(u)||m.isForward(u)?Xc.after:Xc.before;return r.setRelativeSelection(Xc.on(e.first,0),o(e.table)),n.clear(t),Zc(C.none(),!0)}))),(e=>C.some(Zc(C.none(),!0))))};return um(u)&&f&&!_m(l,c)?C.none:dm(u)&&f?o([Nm(1,0)]):mm(u)&&f?o([Nm(-1,0)]):m.isBackward(u)&&f?o([Nm(0,-1),Nm(-1,0)]):m.isForward(u)&&f?o([Nm(0,1),Nm(1,0)]):um(u)&&!f?s:C.none}));return g()},keyup:(e,r,s,l,a)=>Cs(t,n.selectedSelector).fold((()=>{const c=e.raw,i=c.which;return!0===c.shiftKey&&um(i)&&_m(r,l)?((e,t,o,n,r,s,l)=>Re(o,r)&&n===s?C.none():ht(o,"td,th",t).bind((o=>ht(r,"td,th",t).bind((n=>gi(e,t,o,n,l))))))(t,o,r,s,l,a,n.selectRange):C.none()}),C.none)}})(r,s,l,n),i=((e,t,o,n)=>{const r=Em(e);return(e,s)=>{n.clearBeforeUpdate(t),xs(e,s,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(s),r.collapseSelection()}))}})(r,s,l,n);e.on("TableSelectorChange",(e=>i(e.start,e.finish)));const m=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=pm.relative(t.start,t.finish),n=ii(r,o);e.selection.setRng(n)})))},d=e=>0===e.button,u=(()=>{const e=nm(xe.fromDom(s)),t=nm(0);return{touchEnd:o=>{const n=xe.fromDom(o.target);if(ue("td")(n)||ue("th")(n)){const r=e.get(),s=t.get();Re(r,n)&&o.timeStamp-s<300&&(o.preventDefault(),i(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{a.clearstate()})),e.on("mousedown",(e=>{d(e)&&qm(e)&&a.mousedown(Vm(e))})),e.on("mouseover",(e=>{var t;void 0!==(t=e).buttons&&0==(1&t.buttons)||!qm(e)||a.mouseover(Vm(e))})),e.on("mouseup",(e=>{d(e)&&qm(e)&&a.mouseup(Vm(e))})),e.on("touchend",u.touchEnd),e.on("keyup",(t=>{const o=Vm(t);if(o.raw.shiftKey&&um(o.raw.which)){const t=e.selection.getRng(),n=xe.fromDom(t.startContainer),r=xe.fromDom(t.endContainer);c.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{m(o,e)}))}})),e.on("keydown",(o=>{const n=Vm(o);t.hide();const r=e.selection.getRng(),s=xe.fromDom(r.startContainer),l=xe.fromDom(r.endContainer),a=an(fm,gm)(xe.fromDom(e.selection.getStart()));c.keydown(n,s,r.startOffset,l,r.endOffset,a).each((e=>{m(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=xe.fromDom(t.getStart()),r=xe.fromDom(t.getEnd());vs(Vt,[o,r]).fold((()=>n.clear(s)),f)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr(As.firstSelected),e.serializer.addTempAttr(As.lastSelected)})),{getSelectedCells:()=>((e,t,o,n)=>{switch(e.tag){case"none":return t();case"single":return(e=>[e.dom])(e.element);case"multiple":return(e=>E(e,(e=>e.dom)))(e.elements)}})(o.get(),g([])),clearSelectedCells:e=>n.clear(xe.fromDom(e))}},Gm=e=>{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=_(t,(t=>t!==e))},trigger:(...o)=>{const n={};N(e,((e,t)=>{n[e]=o[t]})),N(t,(e=>{e(n)}))}}},Km=e=>({registry:K(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:K(e,(e=>e.trigger))}),Ym=e=>e.slice(0).sort(),Jm=(e,t)=>{const o=_(t,(t=>!D(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+Ym(e).join(", "))})(o)},Qm=e=>((e,t)=>((e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!l(t))throw new Error("The "+e+" fields must be an array. Was: "+t+".");N(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=Ym(e);L(t,((e,o)=>o{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=q(n);P(t,(e=>D(r,e)))||((e,t)=>{throw new Error("All required keys ("+Ym(e).join(", ")+") were not specified. Specified keys were: "+Ym(t).join(", ")+".")})(t,r),e(t,r);const s=_(t,(e=>!o.validate(n[e],e)));return s.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+Ym(e).join(", ")+") were not.")})(s,o.label),n}})(e,t,{validate:d,label:"function"}))(Jm,e),Xm=Qm(["compare","extract","mutate","sink"]),Zm=Qm(["element","start","stop","destroy"]),ed=Qm(["forceDrop","drop","move","delayDrop"]),td=()=>{const e=(()=>{const e=Km({move:Gm(["info"])});return{onEvent:f,reset:f,events:e.registry}})(),t=(()=>{let e=C.none();const t=Km({move:Gm(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=C.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=C.none()},events:t.registry}})();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},od=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},nd=od("ephox-dragster").resolve;var rd=Xm({compare:(e,t)=>gn(t.left-e.left,t.top-e.top),extract:e=>C.some(gn(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:nd("blocker"),...e},o=xe.fromTag("div");return ge(o,"role","presentation"),kt(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),Lm(o,nd("blocker")),Lm(o,t.layerClass),{element:g(o),destroy:()=>{qe(o)}}})(t),n=$m(o.element(),"mousedown",e.forceDrop),r=$m(o.element(),"mouseup",e.drop),s=$m(o.element(),"mousemove",e.move),l=$m(o.element(),"mouseout",e.delayDrop);return Zm({element:o.element,start:e=>{Ie(e,o.element())},stop:()=>{qe(o.element())},destroy:()=>{o.destroy(),r.unbind(),s.unbind(),l.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const sd=od("ephox-snooker").resolve,ld=sd("resizer-bar"),ad=sd("resizer-rows"),cd=sd("resizer-cols"),id=e=>{const t=ct(e.parent(),"."+ld);N(t,qe)},md=(e,t,o)=>{const n=e.origin();N(t,(t=>{t.each((t=>{const r=o(n,t);Lm(r,ld),Ie(e.parent(),r)}))}))},dd=(e,t,o,n,r)=>{const s=pn(o),l=t.isResizable,a=n.length>0?kn.positions(n,o):[],c=a.length>0?((e,t)=>j(e.all,((e,o)=>t(e.element)?[o]:[])))(e,l):[];((e,t,o,n)=>{md(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return kt(s,{position:"absolute",left:t+"px",top:o-3.5+"px",height:"7px",width:n+"px"}),he(s,{"data-row":e,role:"presentation"}),s})(t.row,o.left-e.left,t.y-e.top,n);return Lm(r,ad),r}))})(t,_(a,((e,t)=>O(c,(e=>t===e)))),s,_o(o));const i=r.length>0?Nn.positions(r,o):[],m=i.length>0?((e,t)=>{const o=[];return k(e.grid.columns,(n=>{nn(e,n).map((e=>e.element)).forall(t)&&o.push(n)})),_(o,(o=>{const n=Zo(e,(e=>e.column===o));return P(n,(e=>t(e.element)))}))})(e,l):[];((e,t,o,n)=>{md(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return kt(s,{position:"absolute",left:t-3.5+"px",top:o+"px",height:r+"px",width:"7px"}),he(s,{"data-column":e,role:"presentation"}),s})(t.col,t.x-e.left,o.top-e.top,0,n);return Lm(r,cd),r}))})(t,_(i,((e,t)=>O(m,(e=>t===e)))),s,un(o))},ud=(e,t)=>{if(id(e),e.isResizable(t)){const o=Yo(t),n=ln(o),r=rn(o);dd(o,e,t,n,r)}},fd=(e,t)=>{const o=ct(e.parent(),"."+ld);N(o,t)},gd=e=>{fd(e,(e=>{Ot(e,"display","none")}))},hd=e=>{fd(e,(e=>{Ot(e,"display","block")}))},pd=sd("resizer-bar-dragging"),bd=e=>{const t=(()=>{const e=Km({drag:Gm(["xDelta","yDelta","target"])});let t=C.none();const o=(()=>{const e=Km({drag:Gm(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();return o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))})),{assign:e=>{t=C.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}})(),o=((e,t={})=>{var o;return((e,t,o)=>{let n=!1;const r=Km({start:Gm([]),stop:Gm([])}),s=td(),l=()=>{m.stop(),s.isOn()&&(s.off(),r.trigger.stop())},c=((e,t)=>{let o=null;const n=()=>{a(o)||(clearTimeout(o),o=null)};return{cancel:n,throttle:(...t)=>{n(),o=setTimeout((()=>{o=null,e.apply(null,t)}),200)}}})(l);s.events.move.bind((o=>{t.mutate(e,o.info)}));const i=e=>(...t)=>{n&&e.apply(null,t)},m=t.sink(ed({forceDrop:l,drop:i(l),move:i((e=>{c.cancel(),s.onEvent(e,t)})),delayDrop:i(c.throttle)}),o);return{element:m.element,go:e=>{m.start(e),s.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{m.destroy()},events:r.registry}})(e,null!==(o=t.mode)&&void 0!==o?o:rd,t)})(t,{});let n=C.none();const r=(e,t)=>C.from(pe(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=Wt(e.target,"top");Ot(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=Wt(e.target,"left");Ot(e.target,"left",o+e.xDelta+"px")}))}));const s=(e,t)=>Wt(e,t)-zt(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=s(t,"top");we(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=s(t,"left");we(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),ud(e,o)}))}))}));const l=(n,r)=>{d.trigger.startAdjust(),t.assign(n),ge(n,"data-initial-"+r,Wt(n,r)),Lm(n,pd),Ot(n,"opacity","0.2"),o.go(e.parent())},c=$m(e.parent(),"mousedown",(e=>{var t;t=e.target,Wm(t,ad)&&l(e.target,"top"),(e=>Wm(e,cd))(e.target)&&l(e.target,"left")})),i=t=>Re(t,e.view()),m=$m(e.view(),"mouseover",(t=>{var r;(r=t.target,ht(r,"table",i).filter(Kr)).fold((()=>{nt(t.target)&&id(e)}),(t=>{o.isActive()&&(n=C.some(t),ud(e,t))}))})),d=Km({adjustHeight:Gm(["table","delta","row"]),adjustWidth:Gm(["table","delta","column"]),startAdjust:Gm([])});return{destroy:()=>{c.unbind(),m.unbind(),o.destroy(),id(e)},refresh:t=>{ud(e,t)},on:o.on,off:o.off,hideBars:b(gd,e),showBars:b(hd,e),events:d.registry}},wd=e=>m(e)&&"TABLE"===e.nodeName,vd="bar-",yd=e=>"false"!==pe(e,"data-mce-resize"),xd=e=>{const t=rm(),o=rm(),n=rm();let r,s,l,a;const c=t=>uc(e,t),i=()=>Wr(e)?el():Zs(),m=(t,o,n,m)=>{const d=(e=>{return xt(t=e,"corner-")?((e,t)=>e.substring(7))(t):t;var t})(o),u=Ct(d,"e"),f=xt(d,"n");if(""===s&&Ec(t),""===a&&(e=>{const t=(e=>dn(e)+"px")(e);Sc(e,C.none(),C.some(t)),kc(e)})(t),n!==r&&""!==s){Ot(t,"width",s);const o=i(),l=c(t),a=Wr(e)||u?(e=>tl(e).columns)(t)-1:0;oa(t,n-r,a,o,l)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(s)){const e=parseFloat(s.replace("%",""));Ot(t,"width",n*e/r+"%")}if((e=>/^(\d+(\.\d+)?)px$/.test(e))(s)&&(e=>{const t=Yo(e);on(t)||N(Ht(e),(e=>{const t=Et(e,"width");Ot(e,"width",t),we(e,"width")}))})(t),m!==l&&""!==a){Ot(t,"height",a);const e=f?0:(e=>tl(e).rows)(t)-1;na(t,m-l,e)}};return e.on("init",(()=>{const r=((e,t)=>e.inline?((e,t,o)=>({parent:g(t),view:g(e),origin:g(gn(0,0)),isResizable:o}))(xe.fromDom(e.getBody()),(()=>{const e=xe.fromTag("div");return kt(e,{position:"static",height:"0",width:"0",padding:"0",margin:"0",border:"0"}),Ie(rt(xe.fromDom(document)),e),e})(),t):((e,t)=>{const o=me(e)?(e=>xe.fromDom(Ee(e).dom.documentElement))(e):e;return{parent:g(o),view:g(e),origin:g(gn(0,0)),isResizable:t}})(xe.fromDom(e.getDoc()),t))(e,yd);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return D(t.split(","),"table")})(e)&&Hr(e)){const n=((e,t,o)=>{const n=kn,r=Nn,s=bd(e),l=Km({beforeResize:Gm(["table","type"]),afterResize:Gm(["table","type"]),startDrag:Gm([])});return s.events.adjustHeight.bind((e=>{const t=e.table;l.trigger.beforeResize(t,"row");const o=n.delta(e.delta,t);na(t,o,e.row),l.trigger.afterResize(t,"row")})),s.events.startAdjust.bind((e=>{l.trigger.startDrag()})),s.events.adjustWidth.bind((e=>{const n=e.table;l.trigger.beforeResize(n,"col");const s=r.delta(e.delta,n),a=o(n);oa(n,s,e.column,t,a),l.trigger.afterResize(n,"col")})),{on:s.on,off:s.off,refreshBars:s.refresh,hideBars:s.hideBars,showBars:s.showBars,destroy:s.destroy,events:l.registry}})(r,i(),c);n.on(),n.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),n.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,es(o),ts(o),vd+t.type)})),n.events.afterResize.bind((o=>{const n=o.table,r=n.dom;Xr(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,es(r),ts(r),vd+o.type),e.undoManager.add()})),o.set(n)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(wd(o)){const n=xe.fromDom(o);N(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+Lr(e)+"-columns")})),!Dc(n)&&Ir(e)?Nc(n):!Rc(n)&&Pr(e)&&Ec(n),Oc(n)&&xt(t.origin,vd)&&Ec(n),r=t.width,s=Fr(e)?"":ns(e,o).getOr(""),l=t.height,a=rs(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(wd(o)){const n=xe.fromDom(o),r=t.origin;(e=>xt(e,"corner-"))(r)&&m(n,r,t.width,t.height),Xr(n),cc(e,n.dom,ic)}})),e.on("SwitchMode",(()=>{o.on((t=>{e.mode.isReadOnly()?t.hideBars():t.showBars()}))})),e.on("dragstart dragend",(e=>{o.on((t=>{"dragstart"===e.type?(t.hideBars(),t.off()):(t.on(),t.showBars())}))})),e.on("remove",(()=>{o.on((e=>{e.destroy()})),n.on((t=>{((e,t)=>{e.inline&&qe(t.parent())})(e,t)}))})),{refresh:e=>{o.on((t=>t.refreshBars(xe.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},Cd=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=D(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=D(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0}),t("table_merge_content_on_paste",{processor:"boolean",default:!0})})(e);const t=xd(e),o=Um(e,t),n=fc(e,t,o);return Jc(e,n),((e,t)=>{const o=Qr(e),n=t=>js(Zr(e)).bind((n=>Vt(n,o).map((o=>{const r=Ls(Ps(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),Is(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}};e.add("dom",(e=>({table:Cd(e)})))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/accordion/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/accordion/plugin.min.js new file mode 100644 index 0000000..65b6e70 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/accordion/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const o=e=>t=>typeof t===e,n=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(e),r=o("boolean"),s=e=>null==e,i=e=>!s(e),a=o("function"),l=o("number"),d=e=>()=>e,c=(e,t)=>e===t,m=d(!1);class u{constructor(e,t){this.tag=e,this.value=t}static some(e){return new u(!0,e)}static none(){return u.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?u.some(e(this.value)):u.none()}bind(e){return this.tag?e(this.value):u.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:u.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return i(e)?u.some(e):u.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}u.singletonNone=new u(!1);const g=Array.prototype.indexOf,p=(e,t)=>{return o=e,n=t,g.call(o,n)>-1;var o,n},h=(e,t)=>{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;oe.dom.nodeName.toLowerCase(),w=e=>e.dom.nodeType,b=e=>t=>w(t)===e,N=b(1),T=b(3),A=b(9),C=b(11),S=(e,t,o)=>{if(!(n(o)||r(o)||l(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},x=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},D=(e,t)=>u.from(x(e,t)),E=(e,t)=>{e.dom.removeAttribute(t)},M=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},P={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return M(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return M(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return M(o)},fromDom:M,fromPoint:(e,t,o)=>u.from(e.dom.elementFromPoint(t,o)).map(M)},O=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},k=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,B=O,R=(L=/^\s+|\s+$/g,e=>e.replace(L,""));var L;const $=e=>void 0!==e.style&&a(e.style.getPropertyValue),V=e=>u.from(e.dom.parentNode).map(P.fromDom),I=e=>u.from(e.dom.nextSibling).map(P.fromDom),j=e=>h(e.dom.childNodes,P.fromDom),q=e=>P.fromDom(e.dom.host),F=e=>{const t=T(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=(e=>P.fromDom(e.dom.getRootNode()))(e);return C(o=t)&&i(o.dom.host)?u.some(t):u.none();var o})(P.fromDom(t)).fold((()=>o.body.contains(t)),(n=F,r=q,e=>n(r(e))));var n,r},H=(e,t)=>$(e)?e.style.getPropertyValue(t):"",z=(e,t)=>{V(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},K=(e,t)=>{I(e).fold((()=>{V(e).each((e=>{U(e,t)}))}),(e=>{z(e,t)}))},U=(e,t)=>{e.dom.appendChild(t.dom)},Y=(e,t)=>{f(t,((o,n)=>{const r=0===n?e:t[n-1];K(r,o)}))},_=(e,t)=>{let o=[];return f(j(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(_(e,t))})),o},G=(e,t,o)=>{let n=e.dom;const r=a(o)?o:m;for(;n.parentNode;){n=n.parentNode;const e=P.fromDom(n);if(t(e))return u.some(e);if(r(e))break}return u.none()},J=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Q=(e,t,o)=>G(e,(e=>O(e,t)),o),W=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return k(o)?u.none():u.from(o.querySelector(e)).map(P.fromDom)})(t,e),X=((e,t)=>{const o=t=>e(t)?u.from(t.dom.nodeValue):u.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(T);var Z=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"];const ee=(e,t)=>({element:e,offset:t}),te=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>te(e,t,o).orThunk((()=>u.some(t))))):u.none(),oe=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,ne=(e,t)=>{const o=te(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return ee(o,oe(e,o));const n=e.property().children(o);return n.length>0?ne(e,n[n.length-1]):ee(o,oe(e,o))},re=ne,se={up:d({selector:Q,closest:(e,t,o)=>((e,t,o,n,r)=>((e,t)=>O(e,t))(o,n)?u.some(o):a(r)&&r(o)?u.none():t(o,n,r))(0,Q,e,t,o),predicate:G,all:(e,t)=>{const o=a(t)?t:m;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=P.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r}}),down:d({selector:(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return k(o)?[]:h(o.querySelectorAll(e),P.fromDom)})(t,e),predicate:_}),styles:d({get:(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||F(e)?n:H(o,t)},getRaw:(e,t)=>{const o=e.dom,n=H(o,t);return u.from(n).filter((e=>e.length>0))},set:(e,t,o)=>{((e,t,o)=>{if(!n(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);$(e)&&e.style.setProperty(t,o)})(e.dom,t,o)},remove:(e,t)=>{((e,t)=>{$(e)&&e.style.removeProperty(t)})(e.dom,t),((e,t,o=c)=>e.exists((e=>o(e,t))))(D(e,"style").map(R),"")&&E(e,"style")}}),attrs:d({get:x,set:(e,t,o)=>{S(e.dom,t,o)},remove:E,copyTo:(e,t)=>{const o=(n=e.dom.attributes,r=(e,t)=>(e[t.name]=t.value,e),s={},f(n,((e,t)=>{s=r(s,e)})),s);var n,r,s;((e,t)=>{const o=e.dom;((e,t)=>{const o=y(e);for(let n=0,r=o.length;n{S(o,t,e)}))})(t,o)}}),insert:d({before:z,after:K,afterAll:Y,append:U,appendAll:(e,t)=>{f(t,(t=>{U(e,t)}))},prepend:(e,t)=>{(e=>((e,t)=>{const o=e.dom.childNodes;return u.from(o[0]).map(P.fromDom)})(e))(e).fold((()=>{U(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},wrap:(e,t)=>{z(e,t),U(t,e)}}),remove:d({unwrap:e=>{const t=j(e);t.length>0&&Y(e,t),J(e)},remove:J}),create:d({nu:P.fromTag,clone:e=>P.fromDom(e.dom.cloneNode(!1)),text:P.fromText}),query:d({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:e=>u.from(e.dom.previousSibling).map(P.fromDom),nextSibling:I}),property:d({children:j,name:v,parent:V,document:e=>{return(t=e,A(t)?t:P.fromDom(t.dom.ownerDocument)).dom;var t},isText:T,isComment:e=>8===w(e)||"#comment"===v(e),isElement:N,isSpecial:e=>{const t=v(e);return p(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>N(e)?D(e,"lang"):u.none(),getText:e=>X.get(e),setText:(e,t)=>X.set(e,t),isBoundary:e=>!!N(e)&&("body"===v(e)||p(Z,v(e))),isEmptyTag:e=>!!N(e)&&p(["br","img","hr","input"],v(e)),isNonEditable:e=>N(e)&&"false"===x(e,"contenteditable")}),eq:(e,t)=>e.dom===t.dom,is:B},ie="details",ae="mce-accordion",le="mce-accordion-summary",de="mce-accordion-body",ce="div";var me=tinymce.util.Tools.resolve("tinymce.util.Tools");const ue=e=>"SUMMARY"===(null==e?void 0:e.nodeName),ge=e=>"DETAILS"===(null==e?void 0:e.nodeName),pe=e=>e.hasAttribute("open"),he=e=>{const t=e.selection.getNode();return ue(t)||Boolean(e.dom.getParent(t,ue))},fe=e=>!he(e)&&e.dom.isEditable(e.selection.getNode()),ye=e=>u.from(e.dom.getParent(e.selection.getNode(),ge)),ve=e=>(e.innerHTML='
',e),we=e=>ve(e.dom.create("p")),be=e=>t=>{((e,t)=>{if(ue(null==t?void 0:t.lastChild)){const o=we(e);t.appendChild(o),e.selection.setCursorLocation(o,0)}})(e,t),((e,t)=>{if(!ue(null==t?void 0:t.firstChild)){const o=(e=>ve(e.dom.create("summary")))(e);t.prepend(o),e.selection.setCursorLocation(o,0)}})(e,t)},Ne=e=>{if(!fe(e))return;const o=P.fromDom(e.getBody()),n=(e=>{const o=(new Date).getTime(),n=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return t++,e+"_"+n+t+String(o)})("acc"),r=e.dom.encode(e.selection.getRng().toString()||e.translate("Accordion summary...")),s=e.dom.encode(e.translate("Accordion body...")),i=`${r}`,a=`<${ce} class="${de}">

${s}

`;e.undoManager.transact((()=>{e.insertContent([`
`,i,a,"
"].join("")),W(o,`[data-mce-id="${n}"]`).each((t=>{E(t,"data-mce-id"),W(t,"summary").each((t=>{const o=e.dom.createRng(),n=re(se,t);o.setStart(n.element.dom,n.offset),o.setEnd(n.element.dom,n.offset),e.selection.setRng(o)}))}))}))},Te=(e,t)=>{const o=null!=t?t:!pe(e);return o?e.setAttribute("open","open"):e.removeAttribute("open"),o},Ae=e=>{e.addCommand("InsertAccordion",(()=>Ne(e))),e.addCommand("ToggleAccordion",((t,o)=>((e,t)=>{ye(e).each((o=>{((e,t,o)=>{e.dispatch("ToggledAccordion",{element:t,state:o})})(e,o,Te(o,t))}))})(e,o))),e.addCommand("ToggleAllAccordions",((t,o)=>((e,t)=>{const o=Array.from(e.getBody().querySelectorAll("details"));0!==o.length&&(f(o,(e=>Te(e,null!=t?t:!pe(e)))),((e,t,o)=>{e.dispatch("ToggledAllAccordions",{elements:t,state:o})})(e,o,t))})(e,o))),e.addCommand("RemoveAccordion",(()=>(e=>{ye(e).each((t=>{const{nextSibling:o}=t;o?(e.selection.select(o,!0),e.selection.collapse(!0)):((e,t)=>{const o=we(e);t.insertAdjacentElement("afterend",o),e.selection.setCursorLocation(o,0)})(e,t),t.remove()}))})(e)))};var Ce=tinymce.util.Tools.resolve("tinymce.html.Node");const Se=e=>{var t,o;return null!==(o=null===(t=e.attr("class"))||void 0===t?void 0:t.split(" "))&&void 0!==o?o:[]},xe=(e,t)=>{const o=new Set([...Se(e),...t]),n=Array.from(o);n.length>0&&e.attr("class",n.join(" "))},De=(e,t)=>{const o=((e,o)=>{const n=[];for(let o=0,s=e.length;o0?o.join(" "):null)},Ee=e=>e.name===ie&&p(Se(e),ae),Me=e=>{const t=e.children();let o,n;const r=[];for(let e=0;e{const t=new Ce("br",1);t.attr("data-mce-bogus","1"),e.empty(),e.append(t)};var Oe=tinymce.util.Tools.resolve("tinymce.util.VK");const ke=e=>{(e=>{e.on("keydown",(t=>{(!t.shiftKey&&t.keyCode===Oe.ENTER&&he(e)||(e=>{const t=e.selection.getRng();return ge(t.startContainer)&&t.collapsed&&0===t.startOffset})(e))&&(t.preventDefault(),e.execCommand("ToggleAccordion"))}))})(e),e.on("ExecCommand",(t=>{const o=t.command.toLowerCase();"delete"!==o&&"forwarddelete"!==o||!(e=>ye(e).isSome())(e)||(e=>{me.each(me.grep(e.dom.select("details",e.getBody())),be(e))})(e)}))};var Be=tinymce.util.Tools.resolve("tinymce.Env");const Re=e=>t=>{const o=()=>t.setEnabled(fe(e));return e.on("NodeChange",o),()=>e.off("NodeChange",o)};e.add("accordion",(e=>{(e=>{const t=()=>e.execCommand("InsertAccordion");e.ui.registry.addButton("accordion",{icon:"accordion",tooltip:"Insert accordion",onSetup:Re(e),onAction:t}),e.ui.registry.addMenuItem("accordion",{icon:"accordion",text:"Accordion",onSetup:Re(e),onAction:t}),e.ui.registry.addToggleButton("accordiontoggle",{icon:"accordion-toggle",tooltip:"Toggle accordion",onAction:()=>e.execCommand("ToggleAccordion")}),e.ui.registry.addToggleButton("accordionremove",{icon:"remove",tooltip:"Delete accordion",onAction:()=>e.execCommand("RemoveAccordion")}),e.ui.registry.addContextToolbar("accordion",{predicate:t=>e.dom.is(t,"details")&&e.getBody().contains(t)&&e.dom.isEditable(t.parentNode),items:"accordiontoggle accordionremove",scope:"node",position:"node"})})(e),Ae(e),ke(e),(e=>{e.on("PreInit",(()=>{const{serializer:t,parser:o}=e;o.addNodeFilter(ie,(e=>{for(let t=0;t0)for(let e=0;e{const t=new Set([le]);for(let o=0;o{Be.browser.isSafari()&&e.on("click",(t=>{if(ue(t.target)){const o=t.target,n=e.selection.getRng();n.collapsed&&n.startContainer===o.parentNode&&0===n.startOffset&&e.selection.setCursorLocation(o,0)}}))})(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/advlist/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/advlist/plugin.min.js new file mode 100644 index 0000000..c439480 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/advlist/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),i=t=>null==t,l=t=>!i(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return l(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>e=>l(e)&&t.test(e.nodeName),d=u(/^(OL|UL|DL)$/),g=u(/^(TH|TD)$/),c=t=>i(t)||"default"===t?"":t,h=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;ee.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)&&t.selection.isEditable()})(t,n)&&t.selection.isEditable())})(t,r.parents))),m=(t,s,r,n,i,l)=>{l.length>1?((t,s,r,n,i,l)=>{t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(l,(t=>{const e="OL"===i?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=c(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,i,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return a.from(s)})(t);return s.map((t=>e===t)).getOr(!1)},onSetup:h(t,i)})})(t,s,r,n,i,l):((t,s,r,n,i,l)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",onSetup:h(t,i),onAction:()=>t.queryCommandState(n)||""===l?t.execCommand(n):e(t,i,l)})})(t,s,r,n,i,c(l[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{m(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),m(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/anchor/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/anchor/plugin.min.js new file mode 100644 index 0000000..40a78af --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/anchor/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;ot=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>{const o=e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind,n=u(e)(t);return()=>{o(),n()}}}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t,onSetup:u(e)})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/autolink/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/autolink/plugin.min.js new file mode 100644 index 0000000..12bcf3d --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/autolink/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=4&&b.substr(0,4)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/autoresize/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/autoresize/plugin.min.js new file mode 100644 index 0000000..7513868 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/autoresize/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),g=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},l=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},a=(e,o,r,c)=>{var d;const u=e.dom,h=e.getDoc();if(!h)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void g(e,!0);const m=h.documentElement,f=c?c():i(e),p=null!==(d=n(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=l(u,m,"margin-top",!0),v=l(u,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+f;C<0&&(C=0);const H=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+H>p&&(y=C+H);const b=s(e);b&&y>b?(y=b,g(e,!0)):g(e,!1);const w=o.get();if(w.set&&(e.dom.setStyles(e.getDoc().documentElement,{"min-height":0}),e.dom.setStyles(e.getBody(),{"min-height":"inherit"})),y!==w.totalHeight&&(C-f!==w.contentHeight||!w.set)){const n=y-w.totalHeight;if(u.setStyle(e.getContainer(),"height",y+"px"),o.set({totalHeight:y,contentHeight:C,set:!0}),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t={totalHeight:0,contentHeight:0,set:!1};return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{const n=()=>r(e);e.on("init",(s=>{const r=i(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,s,n)})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{a(e,o,t,n)}))})(e,o)}}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/autosave/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/autosave/plugin.min.js new file mode 100644 index 0000000..d8f70bc --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/autosave/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/charmap/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/charmap/plugin.min.js new file mode 100644 index 0000000..b826ff2 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/charmap/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t)=>{const r=((e,t)=>e.dispatch("insertCustomChar",{chr:t}))(e,t).chr;e.execCommand("mceInsertContent",!1,r)},r=e=>t=>e===t,a=("array",e=>"array"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(n=String).prototype.isPrototypeOf(r)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===n.name)?"string":t;var r,a,n,i})(e));const n=r(null),i=r(void 0),o=e=>"function"==typeof e,s=(!1,()=>false);class l{constructor(e,t){this.tag=e,this.value=t}static some(e){return new l(!0,e)}static none(){return l.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?l.some(e(this.value)):l.none()}bind(e){return this.tag?e(this.value):l.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:l.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?l.none():l.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}l.singletonNone=new l(!1);const c=Array.prototype.push,u=(e,t)=>{const r=e.length,a=new Array(r);for(let n=0;nt=>t.options.get(e),m=h("charmap"),p=h("charmap_append"),d=g.isArray,f="User Defined",y=e=>{return d(e)?(t=e,g.grep(t,(e=>d(e)&&2===e.length))):"function"==typeof e?e():[];var t},b=e=>{const t=((e,t)=>{const r=m(e);r&&(t=[{name:f,characters:y(r)}]);const a=p(e);if(a){const e=g.grep(t,(e=>e.name===f));return e.length?(e[0].characters=[...e[0].characters,...y(a)],t):t.concat({name:f,characters:y(a)})}return t})(e,[{name:"Currency",characters:[[36,"dollar sign"],[162,"cent sign"],[8364,"euro sign"],[163,"pound sign"],[165,"yen sign"],[164,"currency sign"],[8352,"euro-currency sign"],[8353,"colon sign"],[8354,"cruzeiro sign"],[8355,"french franc sign"],[8356,"lira sign"],[8357,"mill sign"],[8358,"naira sign"],[8359,"peseta sign"],[8360,"rupee sign"],[8361,"won sign"],[8362,"new sheqel sign"],[8363,"dong sign"],[8365,"kip sign"],[8366,"tugrik sign"],[8367,"drachma sign"],[8368,"german penny symbol"],[8369,"peso sign"],[8370,"guarani sign"],[8371,"austral sign"],[8372,"hryvnia sign"],[8373,"cedi sign"],[8374,"livre tournois sign"],[8375,"spesmilo sign"],[8376,"tenge sign"],[8377,"indian rupee sign"],[8378,"turkish lira sign"],[8379,"nordic mark sign"],[8380,"manat sign"],[8381,"ruble sign"],[20870,"yen character"],[20803,"yuan character"],[22291,"yuan character, in hong kong and taiwan"],[22278,"yen/yuan character variant one"]]},{name:"Text",characters:[[169,"copyright sign"],[174,"registered sign"],[8482,"trade mark sign"],[8240,"per mille sign"],[181,"micro sign"],[183,"middle dot"],[8226,"bullet"],[8230,"three dot leader"],[8242,"minutes / feet"],[8243,"seconds / inches"],[167,"section sign"],[182,"paragraph sign"],[223,"sharp s / ess-zed"]]},{name:"Quotations",characters:[[8249,"single left-pointing angle quotation mark"],[8250,"single right-pointing angle quotation mark"],[171,"left pointing guillemet"],[187,"right pointing guillemet"],[8216,"left single quotation mark"],[8217,"right single quotation mark"],[8220,"left double quotation mark"],[8221,"right double quotation mark"],[8218,"single low-9 quotation mark"],[8222,"double low-9 quotation mark"],[60,"less-than sign"],[62,"greater-than sign"],[8804,"less-than or equal to"],[8805,"greater-than or equal to"],[8211,"en dash"],[8212,"em dash"],[175,"macron"],[8254,"overline"],[164,"currency sign"],[166,"broken bar"],[168,"diaeresis"],[161,"inverted exclamation mark"],[191,"turned question mark"],[710,"circumflex accent"],[732,"small tilde"],[176,"degree sign"],[8722,"minus sign"],[177,"plus-minus sign"],[247,"division sign"],[8260,"fraction slash"],[215,"multiplication sign"],[185,"superscript one"],[178,"superscript two"],[179,"superscript three"],[188,"fraction one quarter"],[189,"fraction one half"],[190,"fraction three quarters"]]},{name:"Mathematical",characters:[[402,"function / florin"],[8747,"integral"],[8721,"n-ary sumation"],[8734,"infinity"],[8730,"square root"],[8764,"similar to"],[8773,"approximately equal to"],[8776,"almost equal to"],[8800,"not equal to"],[8801,"identical to"],[8712,"element of"],[8713,"not an element of"],[8715,"contains as member"],[8719,"n-ary product"],[8743,"logical and"],[8744,"logical or"],[172,"not sign"],[8745,"intersection"],[8746,"union"],[8706,"partial differential"],[8704,"for all"],[8707,"there exists"],[8709,"diameter"],[8711,"backward difference"],[8727,"asterisk operator"],[8733,"proportional to"],[8736,"angle"]]},{name:"Extended Latin",characters:[[192,"A - grave"],[193,"A - acute"],[194,"A - circumflex"],[195,"A - tilde"],[196,"A - diaeresis"],[197,"A - ring above"],[256,"A - macron"],[198,"ligature AE"],[199,"C - cedilla"],[200,"E - grave"],[201,"E - acute"],[202,"E - circumflex"],[203,"E - diaeresis"],[274,"E - macron"],[204,"I - grave"],[205,"I - acute"],[206,"I - circumflex"],[207,"I - diaeresis"],[298,"I - macron"],[208,"ETH"],[209,"N - tilde"],[210,"O - grave"],[211,"O - acute"],[212,"O - circumflex"],[213,"O - tilde"],[214,"O - diaeresis"],[216,"O - slash"],[332,"O - macron"],[338,"ligature OE"],[352,"S - caron"],[217,"U - grave"],[218,"U - acute"],[219,"U - circumflex"],[220,"U - diaeresis"],[362,"U - macron"],[221,"Y - acute"],[376,"Y - diaeresis"],[562,"Y - macron"],[222,"THORN"],[224,"a - grave"],[225,"a - acute"],[226,"a - circumflex"],[227,"a - tilde"],[228,"a - diaeresis"],[229,"a - ring above"],[257,"a - macron"],[230,"ligature ae"],[231,"c - cedilla"],[232,"e - grave"],[233,"e - acute"],[234,"e - circumflex"],[235,"e - diaeresis"],[275,"e - macron"],[236,"i - grave"],[237,"i - acute"],[238,"i - circumflex"],[239,"i - diaeresis"],[299,"i - macron"],[240,"eth"],[241,"n - tilde"],[242,"o - grave"],[243,"o - acute"],[244,"o - circumflex"],[245,"o - tilde"],[246,"o - diaeresis"],[248,"o slash"],[333,"o macron"],[339,"ligature oe"],[353,"s - caron"],[249,"u - grave"],[250,"u - acute"],[251,"u - circumflex"],[252,"u - diaeresis"],[363,"u - macron"],[253,"y - acute"],[254,"thorn"],[255,"y - diaeresis"],[563,"y - macron"],[913,"Alpha"],[914,"Beta"],[915,"Gamma"],[916,"Delta"],[917,"Epsilon"],[918,"Zeta"],[919,"Eta"],[920,"Theta"],[921,"Iota"],[922,"Kappa"],[923,"Lambda"],[924,"Mu"],[925,"Nu"],[926,"Xi"],[927,"Omicron"],[928,"Pi"],[929,"Rho"],[931,"Sigma"],[932,"Tau"],[933,"Upsilon"],[934,"Phi"],[935,"Chi"],[936,"Psi"],[937,"Omega"],[945,"alpha"],[946,"beta"],[947,"gamma"],[948,"delta"],[949,"epsilon"],[950,"zeta"],[951,"eta"],[952,"theta"],[953,"iota"],[954,"kappa"],[955,"lambda"],[956,"mu"],[957,"nu"],[958,"xi"],[959,"omicron"],[960,"pi"],[961,"rho"],[962,"final sigma"],[963,"sigma"],[964,"tau"],[965,"upsilon"],[966,"phi"],[967,"chi"],[968,"psi"],[969,"omega"]]},{name:"Symbols",characters:[[8501,"alef symbol"],[982,"pi symbol"],[8476,"real part symbol"],[978,"upsilon - hook symbol"],[8472,"Weierstrass p"],[8465,"imaginary part"]]},{name:"Arrows",characters:[[8592,"leftwards arrow"],[8593,"upwards arrow"],[8594,"rightwards arrow"],[8595,"downwards arrow"],[8596,"left right arrow"],[8629,"carriage return"],[8656,"leftwards double arrow"],[8657,"upwards double arrow"],[8658,"rightwards double arrow"],[8659,"downwards double arrow"],[8660,"left right double arrow"],[8756,"therefore"],[8834,"subset of"],[8835,"superset of"],[8836,"not a subset of"],[8838,"subset of or equal to"],[8839,"superset of or equal to"],[8853,"circled plus"],[8855,"circled times"],[8869,"perpendicular"],[8901,"dot operator"],[8968,"left ceiling"],[8969,"right ceiling"],[8970,"left floor"],[8971,"right floor"],[9001,"left-pointing angle bracket"],[9002,"right-pointing angle bracket"],[9674,"lozenge"],[9824,"black spade suit"],[9827,"black club suit"],[9829,"black heart suit"],[9830,"black diamond suit"],[8194,"en space"],[8195,"em space"],[8201,"thin space"],[8204,"zero width non-joiner"],[8205,"zero width joiner"],[8206,"left-to-right mark"],[8207,"right-to-left mark"]]}]);return t.length>1?[{name:"All",characters:(r=t,n=e=>e.characters,(e=>{const t=[];for(let r=0,n=e.length;r{let t=e;return{get:()=>t,set:e=>{t=e}}},v=(e,t,r=0,a)=>{const n=e.indexOf(t,r);return-1!==n&&(!!i(a)||n+t.length<=a)},k=String.fromCodePoint,C=(e,t)=>{const r=[],a=t.toLowerCase();return((e,t)=>{for(let t=0,i=e.length;t!!v(k(e).toLowerCase(),r)||v(t.toLowerCase(),r)||v(t.toLowerCase().replace(/\s+/g,""),r))((n=e[t])[0],n[1],a)&&r.push(n);var n})(e.characters),u(r,(e=>({text:e[1],value:k(e[0]),icon:k(e[0])})))},x="pattern",A=(e,r)=>{const a=()=>[{label:"Search",type:"input",name:x},{type:"collection",name:"results"}],i=1===r.length?w(f):w("All"),o=((e,t)=>{let r=null;const a=()=>{n(r)||(clearTimeout(r),r=null)};return{cancel:a,throttle:(...t)=>{a(),r=setTimeout((()=>{r=null,e.apply(null,t)}),40)}}})((e=>{const t=e.getData().pattern;((e,t)=>{var a,n;(a=r,n=e=>e.name===i.get(),((e,t,r)=>{for(let a=0,n=e.length;a{const a=C(r,t);e.setData({results:a})}))})(e,t)})),c={title:"Special Character",size:"normal",body:1===r.length?{type:"panel",items:a()}:{type:"tabpanel",tabs:u(r,(e=>({title:e.name,name:e.name,items:a()})))},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{pattern:"",results:C(r[0],"")},onAction:(r,a)=>{"results"===a.name&&(t(e,a.value),r.close())},onTabChange:(e,t)=>{i.set(t.newTabName),o.throttle(e)},onChange:(e,t)=>{t.name===x&&o.throttle(e)}};e.windowManager.open(c).focus(x)},q=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("charmap",(e=>{(e=>{const t=e.options.register,r=e=>o(e)||a(e);t("charmap",{processor:r}),t("charmap_append",{processor:r})})(e);const r=b(e);return((e,t)=>{e.addCommand("mceShowCharmap",(()=>{A(e,t)}))})(e,r),(e=>{const t=()=>e.execCommand("mceShowCharmap");e.ui.registry.addButton("charmap",{icon:"insert-character",tooltip:"Special character",onAction:t,onSetup:q(e)}),e.ui.registry.addMenuItem("charmap",{icon:"insert-character",text:"Special character...",onAction:t,onSetup:q(e)})})(e),((e,t)=>{e.ui.registry.addAutocompleter("charmap",{trigger:":",columns:"auto",minChars:2,fetch:(e,r)=>new Promise(((r,a)=>{r(C(t,e))})),onAction:(t,r,a)=>{e.selection.setRng(r),e.insertContent(a),t.hide()}})})(e,r[0]),(e=>({getCharMap:()=>b(e),insertChar:r=>{t(e,r)}}))(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/code/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/code/plugin.min.js new file mode 100644 index 0000000..2359c59 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/code/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/codesample/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/codesample/plugin.min.js new file mode 100644 index 0000000..a190b09 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/codesample/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>!(e=>null==e)(e),n=()=>{};class a{constructor(e,t){this.tag=e,this.value=t}static some(e){return new a(!0,e)}static none(){return a.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?a.some(e(this.value)):a.none()}bind(e){return this.tag?e(this.value):a.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:a.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return t(e)?a.some(e):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);var s=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");const r="undefined"!=typeof window?window:Function("return this;")(),i=function(e,t,n){const a=window.Prism;window.Prism={manual:!0};var s=function(e){var t=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,a={},s={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof r?new r(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);x+=_.value.length,_=_.next){var F=_.value;if(t.length>e.length)return;if(!(F instanceof r)){var A,S=1;if(y){if(!(A=i(v,x,e,m))||A.index>=e.length)break;var $=A.index,z=A.index+A[0].length,E=x;for(E+=_.value.length;$>=E;)E+=(_=_.next).value.length;if(x=E-=_.value.length,_.value instanceof r)continue;for(var C=_;C!==t.tail&&(Ed.reach&&(d.reach=O);var P=_.prev;if(B&&(P=u(t,P,B),x+=B.length),c(t,P,S),_=u(t,P,new r(g,f?s.tokenize(j,f):j,w,j)),T&&u(t,_,T),S>1){var N={cause:g+","+b,reach:O};o(e,t,n,_.prev,x,N),d&&N.reach>d.reach&&(d.reach=N.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function u(e,t,n){var a=t.next,s={value:n,prev:t,next:a};return t.next=s,a.prev=s,e.length++,s}function c(e,t,n){for(var a=t.next,s=0;s"+r.content+""},!e.document)return e.addEventListener?(s.disableWorkerMessageHandler||e.addEventListener("message",(function(t){var n=JSON.parse(t.data),a=n.language,r=n.code,i=n.immediateClose;e.postMessage(s.highlight(r,s.languages[a],a)),i&&e.close()}),!1),s):s;var d=s.util.currentScript();function g(){s.manual||s.highlightAll()}if(d&&(s.filename=d.src,d.hasAttribute("data-manual")&&(s.manual=!0)),!s.manual){var p=document.readyState;"loading"===p||"interactive"===p&&d&&d.defer?document.addEventListener("DOMContentLoaded",g):window.requestAnimationFrame?window.requestAnimationFrame(g):window.setTimeout(g,16)}return s}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});return s.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,a,s,r){if(n.language===a){var i=n.tokenStack=[];n.code=n.code.replace(s,(function(e){if("function"==typeof r&&!r(e))return e;for(var s,o=i.length;-1!==n.code.indexOf(s=t(a,o));)++o;return i[o]=e,s})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,a){if(n.language===a&&n.tokenStack){n.grammar=e.languages[a];var s=0,r=Object.keys(n.tokenStack);!function i(o){for(var l=0;l=r.length);l++){var u=o[l];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=r[s],d=n.tokenStack[c],g="string"==typeof u?u:u.content,p=t(a,c),b=g.indexOf(p);if(b>-1){++s;var h=g.substring(0,b),f=new e.Token(a,e.tokenize(d,n.grammar),"language-"+a,d),m=g.substring(b+p.length),y=[];h&&y.push.apply(y,i([h])),y.push(f),m&&y.push.apply(y,i([m])),"string"==typeof u?o.splice.apply(o,[l,1].concat(y)):u.content=y}}else u.content&&i(u.content)}return o}(n.tokens)}}}})}(s),s.languages.c=s.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),s.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),s.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},s.languages.c.string],char:s.languages.c.char,comment:s.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:s.languages.c}}}}),s.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete s.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(s),function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,a){return RegExp(t(e,n),a||"")}function a(e,t){for(var n=0;n>/g,(function(){return"(?:"+e+")"}));return e.replace(/<>/g,"[^\\s\\S]")}var s="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var u=l(r),c=RegExp(l(s+" "+r+" "+i+" "+o)),d=l(r+" "+i+" "+o),g=l(s+" "+r+" "+o),p=a(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),b=a(/\((?:[^()]|<>)*\)/.source,2),h=/@?\b[A-Za-z_]\w*\b/.source,f=t(/<<0>>(?:\s*<<1>>)?/.source,[h,p]),m=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,f]),y=/\[\s*(?:,\s*)*\]/.source,w=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[m,y]),k=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[p,b,y]),v=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[k]),_=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[v,m,y]),x={keyword:c,punctuation:/[<>()?,.:[\]]/},F=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,A=/"(?:\\.|[^\\"\r\n])*"/.source,S=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[S]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[A]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[h,_]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[h]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[u,f]),lookbehind:!0,inside:x},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\bwhere\s+)<<0>>/.source,[h]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[w]),lookbehind:!0,inside:x},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[_,g,h]),inside:x}],keyword:c,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[h]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[b]),lookbehind:!0,alias:"class-name",inside:x},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[_,m]),inside:x,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[_]),lookbehind:!0,inside:x,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[h,p]),inside:{function:n(/^<<0>>/.source,[h]),generic:{pattern:RegExp(p),alias:"class-name",inside:x}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[u,f,h,_,c.source,b,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[f,b]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:c,"class-name":{pattern:RegExp(_),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var $=A+"|"+F,z=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[$]),E=a(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[z]),2),C=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,j=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[m,E]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[C,j]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[C]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[E]),inside:e.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var B=/:[^}\r\n]+/.source,T=a(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[z]),2),O=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[T,B]),P=a(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[$]),2),N=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[P,B]);function R(t,a){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[a,B]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[O]),lookbehind:!0,greedy:!0,inside:R(O,T)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[N]),lookbehind:!0,greedy:!0,inside:R(N,P)}],char:{pattern:RegExp(F),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(s),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(s),function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,a={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[a,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:a.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:a.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:a.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(s),s.languages.javascript=s.languages.extend("clike",{"class-name":[s.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),s.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,s.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:s.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:s.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:s.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:s.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:s.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),s.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:s.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),s.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),s.languages.markup&&(s.languages.markup.tag.addInlined("script","javascript"),s.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),s.languages.js=s.languages.javascript,s.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},s.languages.markup.tag.inside["attr-value"].inside.entity=s.languages.markup.entity,s.languages.markup.doctype.inside["internal-subset"].inside=s.languages.markup,s.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(s.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:s.languages[t]},n.cdata=/^$/i;var a={"included-cdata":{pattern://i,inside:n}};a["language-"+t]={pattern:/[\s\S]+/,inside:s.languages[t]};var r={};r[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:a},s.languages.insertBefore("markup","cdata",r)}}),Object.defineProperty(s.languages.markup.tag,"addAttribute",{value:function(e,t){s.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:s.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),s.languages.html=s.languages.markup,s.languages.mathml=s.languages.markup,s.languages.svg=s.languages.markup,s.languages.xml=s.languages.extend("markup",{}),s.languages.ssml=s.languages.xml,s.languages.atom=s.languages.xml,s.languages.rss=s.languages.xml,function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,s=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,r=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:s,punctuation:r};var i={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:i}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:i}}];e.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:s,punctuation:r}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){/<\?/.test(t.code)&&e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(s),s.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},s.languages.python["string-interpolation"].inside.interpolation.inside.rest=s.languages.python,s.languages.py=s.languages.python,function(e){e.languages.ruby=e.languages.extend("clike",{comment:{pattern:/#.*|^=begin\s[\s\S]*?^=end/m,greedy:!0},"class-name":{pattern:/(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,operator:/\.{2,3}|&\.|===||[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,punctuation:/[(){}[\].,;]/}),e.languages.insertBefore("ruby","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}});var t={pattern:/((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,lookbehind:!0,inside:{content:{pattern:/^(#\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.ruby},delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"}}};delete e.languages.ruby.function;var n="(?:"+[/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source].join("|")+")",a=/(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;e.languages.insertBefore("ruby","keyword",{"regex-literal":[{pattern:RegExp(/%r/.source+n+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:[{pattern:RegExp(/(^|[^:]):/.source+a),lookbehind:!0,greedy:!0},{pattern:RegExp(/([\r\n{(,][ \t]*)/.source+a+/(?=:(?!:))/.source),lookbehind:!0,greedy:!0}],"method-definition":{pattern:/(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,lookbehind:!0,inside:{function:/\b\w+$/,keyword:/^self\b/,"class-name":/^\w+/,punctuation:/\./}}}),e.languages.insertBefore("ruby","string",{"string-literal":[{pattern:RegExp(/%[qQiIwWs]?/.source+n),greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?/}},interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?'|'$/}},string:/[\s\S]+/}}],"command-literal":[{pattern:RegExp(/%x/.source+n),greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}},{pattern:/`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}}]}),delete e.languages.ruby.string,e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,constant:/\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/}),e.languages.rb=e.languages.ruby}(s),window.Prism=a,s}(),o=e=>t=>t.options.get(e),l=o("codesample_languages"),u=o("codesample_global_prismjs"),c=e=>r.Prism&&u(e)?r.Prism:i,d=e=>t(e)&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-"),g=e=>{const t=e.selection?e.selection.getNode():null;return d(t)?a.some(t):a.none()},p=e=>{const t=(e=>l(e)||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}])(e),n=(r=t,((e,t)=>0""),(e=>e.value));var r;const i=((e,t)=>g(e).fold((()=>t),(e=>{const n=e.className.match(/language-(\w+)/);return n?n[1]:t})))(e,n),o=(e=>g(e).bind((e=>a.from(e.textContent))).getOr(""))(e);e.windowManager.open({title:"Insert/Edit Code Sample",size:"large",body:{type:"panel",items:[{type:"listbox",name:"language",label:"Language",items:t},{type:"textarea",name:"code",label:"Code view"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{language:i,code:o},onSubmit:t=>{const n=t.getData();((e,t,n)=>{const a=e.dom;e.undoManager.transact((()=>{const r=g(e);return n=s.DOM.encode(n),r.fold((()=>{e.insertContent('
'+n+"
");const s=a.select("#__new")[0];a.setAttrib(s,"id",null),e.selection.select(s)}),(s=>{a.setAttrib(s,"class","language-"+t),s.innerHTML=n,c(e).highlightElement(s),e.selection.select(s)}))}))})(e,n.language,n.code),t.close()}})},b=(h=/^\s+|\s+$/g,e=>e.replace(h,""));var h,f=tinymce.util.Tools.resolve("tinymce.util.Tools");const m=(e,t=n)=>n=>{const a=()=>{n.setEnabled(e.selection.isEditable()),t(n)};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("codesample",(e=>{(e=>{const t=e.options.register;t("codesample_languages",{processor:"object[]"}),t("codesample_global_prismjs",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreProcess",(t=>{const n=e.dom,a=n.select("pre[contenteditable=false]",t.node);f.each(f.grep(a,d),(e=>{const t=e.textContent;let a;for(n.setAttrib(e,"class",b(n.getAttrib(e,"class"))),n.setAttrib(e,"contentEditable",null),n.setAttrib(e,"data-mce-highlighted",null);a=e.firstChild;)e.removeChild(a);n.add(e,"code").textContent=t}))})),e.on("SetContent",(()=>{const t=e.dom,n=f.grep(t.select("pre"),(e=>d(e)&&"true"!==t.getAttrib(e,"data-mce-highlighted")));n.length&&e.undoManager.transact((()=>{f.each(n,(n=>{var a;f.each(t.select("br",n),(n=>{t.replace(e.getDoc().createTextNode("\n"),n)})),n.innerHTML=t.encode(null!==(a=n.textContent)&&void 0!==a?a:""),c(e).highlightElement(n),t.setAttrib(n,"data-mce-highlighted",!0),n.className=b(n.className)}))}))})),e.on("PreInit",(()=>{e.parser.addNodeFilter("pre",(e=>{var t;for(let n=0,a=e.length;n{const t=()=>e.execCommand("codesample");e.ui.registry.addToggleButton("codesample",{icon:"code-sample",tooltip:"Insert/edit code sample",onAction:t,onSetup:m(e,(t=>{t.setActive((e=>{const t=e.selection.getStart();return e.dom.is(t,'pre[class*="language-"]')})(e))}))}),e.ui.registry.addMenuItem("codesample",{text:"Code sample...",icon:"code-sample",onAction:t,onSetup:m(e)})})(e),(e=>{e.addCommand("codesample",(()=>{const t=e.selection.getNode();e.selection.isCollapsed()||d(t)?p(e):e.formatter.toggle("code")}))})(e),e.on("dblclick",(t=>{d(t.target)&&p(e)}))}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/directionality/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/directionality/plugin.min.js new file mode 100644 index 0000000..169a806 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/directionality/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(11),y=(t,e)=>{t.dom.removeAttribute(e)},p=t=>d(t.dom.host),w=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=(t=>d(t.dom.getRootNode()))(t);return v(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=w,i=p,t=>r(i(t))));var r,i},b=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||w(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",S=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r{const o=t.length,r=new Array(o);for(let n=0;nh(t,e))))(t),N=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const A=(t,e,n)=>{u(e,(e=>{const c=d(e),m=N(c),f=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(c,m);var v;(v=f,(t=>a.from(t.dom.parentNode).map(d))(v).filter(g)).each((e=>{if(t.setStyle(f.dom,"direction",null),b(e)===n?y(f,"dir"):((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(f,"dir",n),b(f)!==n&&t.setStyle(f.dom,"direction",n),m){const e=S(f,"li[dir],li[style]");u(e,(e=>{y(e,"dir"),t.setStyle(e.dom,"direction",null)}))}}))}))},T=(t,e)=>{t.selection.isEditable()&&(A(t.dom,t.selection.getSelectedBlocks(),e),t.nodeChanged())},C=(t,e)=>o=>{const r=r=>{const n=d(r.element);o.setActive(b(n)===e),o.setEnabled(t.selection.isEditable())};return t.on("NodeChange",r),o.setEnabled(t.selection.isEditable()),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{T(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{T(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:C(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:C(t,"rtl")})})(t)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.js b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.js new file mode 100644 index 0000000..6fcec71 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.js @@ -0,0 +1 @@ +window.tinymce.Resource.add("tinymce.plugins.emoticons",{100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:'💯',fitzpatrick_scale:false,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:'🔢',fitzpatrick_scale:false,category:"symbols"},grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:'😀',fitzpatrick_scale:false,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:'😬',fitzpatrick_scale:false,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:'😁',fitzpatrick_scale:false,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:'😂',fitzpatrick_scale:false,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:'🤣',fitzpatrick_scale:false,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:'🥳',fitzpatrick_scale:false,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:'😃',fitzpatrick_scale:false,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:'😄',fitzpatrick_scale:false,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:'😅',fitzpatrick_scale:false,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:'😆',fitzpatrick_scale:false,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:'😇',fitzpatrick_scale:false,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:'😉',fitzpatrick_scale:false,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:'😊',fitzpatrick_scale:false,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:'🙂',fitzpatrick_scale:false,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:'🙃',fitzpatrick_scale:false,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:'☺️',fitzpatrick_scale:false,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:'😋',fitzpatrick_scale:false,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:'😌',fitzpatrick_scale:false,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:'😍',fitzpatrick_scale:false,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:'🥰',fitzpatrick_scale:false,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'😘',fitzpatrick_scale:false,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:'😗',fitzpatrick_scale:false,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:'😙',fitzpatrick_scale:false,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'😚',fitzpatrick_scale:false,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:'😜',fitzpatrick_scale:false,category:"people"},zany:{keywords:["face","goofy","crazy"],char:'🤪',fitzpatrick_scale:false,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:'🤨',fitzpatrick_scale:false,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:'🧐',fitzpatrick_scale:false,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:'😝',fitzpatrick_scale:false,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:'😛',fitzpatrick_scale:false,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:'🤑',fitzpatrick_scale:false,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:'🤓',fitzpatrick_scale:false,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:'😎',fitzpatrick_scale:false,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:'🤩',fitzpatrick_scale:false,category:"people"},clown_face:{keywords:["face"],char:'🤡',fitzpatrick_scale:false,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:'🤠',fitzpatrick_scale:false,category:"people"},hugs:{keywords:["face","smile","hug"],char:'🤗',fitzpatrick_scale:false,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:'😏',fitzpatrick_scale:false,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:'😶',fitzpatrick_scale:false,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:'😐',fitzpatrick_scale:false,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:'😑',fitzpatrick_scale:false,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:'😒',fitzpatrick_scale:false,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:'🙄',fitzpatrick_scale:false,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:'🤔',fitzpatrick_scale:false,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:'🤥',fitzpatrick_scale:false,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:'🤭',fitzpatrick_scale:false,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:'🤫',fitzpatrick_scale:false,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:'🤬',fitzpatrick_scale:false,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:'🤯',fitzpatrick_scale:false,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:'😳',fitzpatrick_scale:false,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:'😞',fitzpatrick_scale:false,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:'😟',fitzpatrick_scale:false,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:'😠',fitzpatrick_scale:false,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:'😡',fitzpatrick_scale:false,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:'😔',fitzpatrick_scale:false,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:'😕',fitzpatrick_scale:false,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:'🙁',fitzpatrick_scale:false,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:'☹',fitzpatrick_scale:false,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:'😣',fitzpatrick_scale:false,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:'😖',fitzpatrick_scale:false,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:'😫',fitzpatrick_scale:false,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:'😩',fitzpatrick_scale:false,category:"people"},pleading:{keywords:["face","begging","mercy"],char:'🥺',fitzpatrick_scale:false,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:'😤',fitzpatrick_scale:false,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:'😮',fitzpatrick_scale:false,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:'😱',fitzpatrick_scale:false,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:'😨',fitzpatrick_scale:false,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:'😰',fitzpatrick_scale:false,category:"people"},hushed:{keywords:["face","woo","shh"],char:'😯',fitzpatrick_scale:false,category:"people"},frowning:{keywords:["face","aw","what"],char:'😦',fitzpatrick_scale:false,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:'😧',fitzpatrick_scale:false,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:'😢',fitzpatrick_scale:false,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:'😥',fitzpatrick_scale:false,category:"people"},drooling_face:{keywords:["face"],char:'🤤',fitzpatrick_scale:false,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:'😪',fitzpatrick_scale:false,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:'😓',fitzpatrick_scale:false,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:'🥵',fitzpatrick_scale:false,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:'🥶',fitzpatrick_scale:false,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:'😭',fitzpatrick_scale:false,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:'😵',fitzpatrick_scale:false,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:'😲',fitzpatrick_scale:false,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:'🤐',fitzpatrick_scale:false,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:'🤢',fitzpatrick_scale:false,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:'🤧',fitzpatrick_scale:false,category:"people"},vomiting:{keywords:["face","sick"],char:'🤮',fitzpatrick_scale:false,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:'😷',fitzpatrick_scale:false,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:'🤒',fitzpatrick_scale:false,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:'🤕',fitzpatrick_scale:false,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:'🥴',fitzpatrick_scale:false,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:'😴',fitzpatrick_scale:false,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:'💤',fitzpatrick_scale:false,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:'💩',fitzpatrick_scale:false,category:"people"},smiling_imp:{keywords:["devil","horns"],char:'😈',fitzpatrick_scale:false,category:"people"},imp:{keywords:["devil","angry","horns"],char:'👿',fitzpatrick_scale:false,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:'👹',fitzpatrick_scale:false,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:'👺',fitzpatrick_scale:false,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:'💀',fitzpatrick_scale:false,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:'👻',fitzpatrick_scale:false,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:'👽',fitzpatrick_scale:false,category:"people"},robot:{keywords:["computer","machine","bot"],char:'🤖',fitzpatrick_scale:false,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:'😺',fitzpatrick_scale:false,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:'😸',fitzpatrick_scale:false,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:'😹',fitzpatrick_scale:false,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:'😻',fitzpatrick_scale:false,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:'😼',fitzpatrick_scale:false,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:'😽',fitzpatrick_scale:false,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:'🙀',fitzpatrick_scale:false,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:'😿',fitzpatrick_scale:false,category:"people"},pouting_cat:{keywords:["animal","cats"],char:'😾',fitzpatrick_scale:false,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:'🤲',fitzpatrick_scale:true,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:'🙌',fitzpatrick_scale:true,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:'👏',fitzpatrick_scale:true,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:'👋',fitzpatrick_scale:true,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:'🤙',fitzpatrick_scale:true,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:'👍',fitzpatrick_scale:true,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:'👎',fitzpatrick_scale:true,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:'👊',fitzpatrick_scale:true,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:'✊',fitzpatrick_scale:true,category:"people"},fist_left:{keywords:["hand","fistbump"],char:'🤛',fitzpatrick_scale:true,category:"people"},fist_right:{keywords:["hand","fistbump"],char:'🤜',fitzpatrick_scale:true,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:'✌',fitzpatrick_scale:true,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:'👌',fitzpatrick_scale:true,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:'✋',fitzpatrick_scale:true,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:'🤚',fitzpatrick_scale:true,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:'👐',fitzpatrick_scale:true,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:'💪',fitzpatrick_scale:true,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:'🙏',fitzpatrick_scale:true,category:"people"},foot:{keywords:["kick","stomp"],char:'🦶',fitzpatrick_scale:true,category:"people"},leg:{keywords:["kick","limb"],char:'🦵',fitzpatrick_scale:true,category:"people"},handshake:{keywords:["agreement","shake"],char:'🤝',fitzpatrick_scale:false,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:'☝',fitzpatrick_scale:true,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:'👆',fitzpatrick_scale:true,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:'👇',fitzpatrick_scale:true,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:'👈',fitzpatrick_scale:true,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:'👉',fitzpatrick_scale:true,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:'🖕',fitzpatrick_scale:true,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:'🖐',fitzpatrick_scale:true,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:'🤟',fitzpatrick_scale:true,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:'🤘',fitzpatrick_scale:true,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:'🤞',fitzpatrick_scale:true,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:'🖖',fitzpatrick_scale:true,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:'✍',fitzpatrick_scale:true,category:"people"},selfie:{keywords:["camera","phone"],char:'🤳',fitzpatrick_scale:true,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:'💅',fitzpatrick_scale:true,category:"people"},lips:{keywords:["mouth","kiss"],char:'👄',fitzpatrick_scale:false,category:"people"},tooth:{keywords:["teeth","dentist"],char:'🦷',fitzpatrick_scale:false,category:"people"},tongue:{keywords:["mouth","playful"],char:'👅',fitzpatrick_scale:false,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:'👂',fitzpatrick_scale:true,category:"people"},nose:{keywords:["smell","sniff"],char:'👃',fitzpatrick_scale:true,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:'👁',fitzpatrick_scale:false,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:'👀',fitzpatrick_scale:false,category:"people"},brain:{keywords:["smart","intelligent"],char:'🧠',fitzpatrick_scale:false,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:'👤',fitzpatrick_scale:false,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:'👥',fitzpatrick_scale:false,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:'🗣',fitzpatrick_scale:false,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:'👶',fitzpatrick_scale:true,category:"people"},child:{keywords:["gender-neutral","young"],char:'🧒',fitzpatrick_scale:true,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:'👦',fitzpatrick_scale:true,category:"people"},girl:{keywords:["female","woman","teenager"],char:'👧',fitzpatrick_scale:true,category:"people"},adult:{keywords:["gender-neutral","person"],char:'🧑',fitzpatrick_scale:true,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:'👨',fitzpatrick_scale:true,category:"people"},woman:{keywords:["female","girls","lady"],char:'👩',fitzpatrick_scale:true,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:'👱‍♀️',fitzpatrick_scale:true,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:'👱',fitzpatrick_scale:true,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:'🧔',fitzpatrick_scale:true,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:'🧓',fitzpatrick_scale:true,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:'👴',fitzpatrick_scale:true,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:'👵',fitzpatrick_scale:true,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:'👲',fitzpatrick_scale:true,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:'🧕',fitzpatrick_scale:true,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:'👳‍♀️',fitzpatrick_scale:true,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:'👳',fitzpatrick_scale:true,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:'👮‍♀️',fitzpatrick_scale:true,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:'👮',fitzpatrick_scale:true,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:'👷‍♀️',fitzpatrick_scale:true,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:'👷',fitzpatrick_scale:true,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:'💂‍♀️',fitzpatrick_scale:true,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:'💂',fitzpatrick_scale:true,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:'🕵️‍♀️',fitzpatrick_scale:true,category:"people"},male_detective:{keywords:["human","spy","detective"],char:'🕵',fitzpatrick_scale:true,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:'👩‍⚕️',fitzpatrick_scale:true,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:'👨‍⚕️',fitzpatrick_scale:true,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:'👩‍🌾',fitzpatrick_scale:true,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:'👨‍🌾',fitzpatrick_scale:true,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:'👩‍🍳',fitzpatrick_scale:true,category:"people"},man_cook:{keywords:["chef","man","human"],char:'👨‍🍳',fitzpatrick_scale:true,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:'👩‍🎓',fitzpatrick_scale:true,category:"people"},man_student:{keywords:["graduate","man","human"],char:'👨‍🎓',fitzpatrick_scale:true,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:'👩‍🎤',fitzpatrick_scale:true,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:'👨‍🎤',fitzpatrick_scale:true,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:'👩‍🏫',fitzpatrick_scale:true,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:'👨‍🏫',fitzpatrick_scale:true,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:'👩‍🏭',fitzpatrick_scale:true,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:'👨‍🏭',fitzpatrick_scale:true,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:'👩‍💻',fitzpatrick_scale:true,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:'👨‍💻',fitzpatrick_scale:true,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:'👩‍💼',fitzpatrick_scale:true,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:'👨‍💼',fitzpatrick_scale:true,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:'👩‍🔧',fitzpatrick_scale:true,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:'👨‍🔧',fitzpatrick_scale:true,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:'👩‍🔬',fitzpatrick_scale:true,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:'👨‍🔬',fitzpatrick_scale:true,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:'👩‍🎨',fitzpatrick_scale:true,category:"people"},man_artist:{keywords:["painter","man","human"],char:'👨‍🎨',fitzpatrick_scale:true,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:'👩‍🚒',fitzpatrick_scale:true,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:'👨‍🚒',fitzpatrick_scale:true,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:'👩‍✈️',fitzpatrick_scale:true,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:'👨‍✈️',fitzpatrick_scale:true,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:'👩‍🚀',fitzpatrick_scale:true,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:'👨‍🚀',fitzpatrick_scale:true,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:'👩‍⚖️',fitzpatrick_scale:true,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:'👨‍⚖️',fitzpatrick_scale:true,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:'🦸‍♀️',fitzpatrick_scale:true,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:'🦸‍♂️',fitzpatrick_scale:true,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:'🦹‍♀️',fitzpatrick_scale:true,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:'🦹‍♂️',fitzpatrick_scale:true,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:'🤶',fitzpatrick_scale:true,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:'🎅',fitzpatrick_scale:true,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:'🧙‍♀️',fitzpatrick_scale:true,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:'🧙‍♂️',fitzpatrick_scale:true,category:"people"},woman_elf:{keywords:["woman","female"],char:'🧝‍♀️',fitzpatrick_scale:true,category:"people"},man_elf:{keywords:["man","male"],char:'🧝‍♂️',fitzpatrick_scale:true,category:"people"},woman_vampire:{keywords:["woman","female"],char:'🧛‍♀️',fitzpatrick_scale:true,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:'🧛‍♂️',fitzpatrick_scale:true,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:'🧟‍♀️',fitzpatrick_scale:false,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:'🧟‍♂️',fitzpatrick_scale:false,category:"people"},woman_genie:{keywords:["woman","female"],char:'🧞‍♀️',fitzpatrick_scale:false,category:"people"},man_genie:{keywords:["man","male"],char:'🧞‍♂️',fitzpatrick_scale:false,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:'🧜‍♀️',fitzpatrick_scale:true,category:"people"},merman:{keywords:["man","male","triton"],char:'🧜‍♂️',fitzpatrick_scale:true,category:"people"},woman_fairy:{keywords:["woman","female"],char:'🧚‍♀️',fitzpatrick_scale:true,category:"people"},man_fairy:{keywords:["man","male"],char:'🧚‍♂️',fitzpatrick_scale:true,category:"people"},angel:{keywords:["heaven","wings","halo"],char:'👼',fitzpatrick_scale:true,category:"people"},pregnant_woman:{keywords:["baby"],char:'🤰',fitzpatrick_scale:true,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:'🤱',fitzpatrick_scale:true,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:'👸',fitzpatrick_scale:true,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:'🤴',fitzpatrick_scale:true,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:'👰',fitzpatrick_scale:true,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:'🤵',fitzpatrick_scale:true,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:'🏃‍♀️',fitzpatrick_scale:true,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:'🏃',fitzpatrick_scale:true,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:'🚶‍♀️',fitzpatrick_scale:true,category:"people"},walking_man:{keywords:["human","feet","steps"],char:'🚶',fitzpatrick_scale:true,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:'💃',fitzpatrick_scale:true,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:'🕺',fitzpatrick_scale:true,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:'👯',fitzpatrick_scale:false,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:'👯‍♂️',fitzpatrick_scale:false,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:'👫',fitzpatrick_scale:false,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:'👬',fitzpatrick_scale:false,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:'👭',fitzpatrick_scale:false,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:'🙇‍♀️',fitzpatrick_scale:true,category:"people"},bowing_man:{keywords:["man","male","boy"],char:'🙇',fitzpatrick_scale:true,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:'🤦‍♂️',fitzpatrick_scale:true,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:'🤦‍♀️',fitzpatrick_scale:true,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:'🤷',fitzpatrick_scale:true,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:'🤷‍♂️',fitzpatrick_scale:true,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:'💁',fitzpatrick_scale:true,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:'💁‍♂️',fitzpatrick_scale:true,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:'🙅',fitzpatrick_scale:true,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:'🙅‍♂️',fitzpatrick_scale:true,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:'🙆',fitzpatrick_scale:true,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:'🙆‍♂️',fitzpatrick_scale:true,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:'🙋',fitzpatrick_scale:true,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:'🙋‍♂️',fitzpatrick_scale:true,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:'🙎',fitzpatrick_scale:true,category:"people"},pouting_man:{keywords:["male","boy","man"],char:'🙎‍♂️',fitzpatrick_scale:true,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:'🙍',fitzpatrick_scale:true,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:'🙍‍♂️',fitzpatrick_scale:true,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:'💇',fitzpatrick_scale:true,category:"people"},haircut_man:{keywords:["male","boy","man"],char:'💇‍♂️',fitzpatrick_scale:true,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:'💆',fitzpatrick_scale:true,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:'💆‍♂️',fitzpatrick_scale:true,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:'🧖‍♀️',fitzpatrick_scale:true,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:'🧖‍♂️',fitzpatrick_scale:true,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'💑',fitzpatrick_scale:false,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'👩‍❤️‍👩',fitzpatrick_scale:false,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'👨‍❤️‍👨',fitzpatrick_scale:false,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'💏',fitzpatrick_scale:false,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'👩‍❤️‍💋‍👩',fitzpatrick_scale:false,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:'👨‍❤️‍💋‍👨',fitzpatrick_scale:false,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:'👪',fitzpatrick_scale:false,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:'👨‍👩‍👧',fitzpatrick_scale:false,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👩‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👩‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'👨‍👩‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👦',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👧',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👦',fitzpatrick_scale:false,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👧',fitzpatrick_scale:false,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:'👩‍👦',fitzpatrick_scale:false,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:'👩‍👧',fitzpatrick_scale:false,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:'👩‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:'👩‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:'👩‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:'👨‍👦',fitzpatrick_scale:false,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:'👨‍👧',fitzpatrick_scale:false,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:'👨‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:'👨‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:'👨‍👧‍👧',fitzpatrick_scale:false,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:'🧶',fitzpatrick_scale:false,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:'🧵',fitzpatrick_scale:false,category:"people"},coat:{keywords:["jacket"],char:'🧥',fitzpatrick_scale:false,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:'🥼',fitzpatrick_scale:false,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:'👚',fitzpatrick_scale:false,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:'👕',fitzpatrick_scale:false,category:"people"},jeans:{keywords:["fashion","shopping"],char:'👖',fitzpatrick_scale:false,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:'👔',fitzpatrick_scale:false,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:'👗',fitzpatrick_scale:false,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:'👙',fitzpatrick_scale:false,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:'👘',fitzpatrick_scale:false,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:'💄',fitzpatrick_scale:false,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:'💋',fitzpatrick_scale:false,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:'👣',fitzpatrick_scale:false,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:'🥿',fitzpatrick_scale:false,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:'👠',fitzpatrick_scale:false,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:'👡',fitzpatrick_scale:false,category:"people"},boot:{keywords:["shoes","fashion"],char:'👢',fitzpatrick_scale:false,category:"people"},mans_shoe:{keywords:["fashion","male"],char:'👞',fitzpatrick_scale:false,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:'👟',fitzpatrick_scale:false,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:'🥾',fitzpatrick_scale:false,category:"people"},socks:{keywords:["stockings","clothes"],char:'🧦',fitzpatrick_scale:false,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:'🧤',fitzpatrick_scale:false,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:'🧣',fitzpatrick_scale:false,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:'👒',fitzpatrick_scale:false,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:'🎩',fitzpatrick_scale:false,category:"people"},billed_hat:{keywords:["cap","baseball"],char:'🧢',fitzpatrick_scale:false,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:'⛑',fitzpatrick_scale:false,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:'🎓',fitzpatrick_scale:false,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:'👑',fitzpatrick_scale:false,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:'🎒',fitzpatrick_scale:false,category:"people"},luggage:{keywords:["packing","travel"],char:'🧳',fitzpatrick_scale:false,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:'👝',fitzpatrick_scale:false,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:'👛',fitzpatrick_scale:false,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:'👜',fitzpatrick_scale:false,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:'💼',fitzpatrick_scale:false,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:'👓',fitzpatrick_scale:false,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:'🕶',fitzpatrick_scale:false,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:'🥽',fitzpatrick_scale:false,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:'💍',fitzpatrick_scale:false,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:'🌂',fitzpatrick_scale:false,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:'🐶',fitzpatrick_scale:false,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:'🐱',fitzpatrick_scale:false,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:'🐭',fitzpatrick_scale:false,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:'🐹',fitzpatrick_scale:false,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:'🐰',fitzpatrick_scale:false,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:'🦊',fitzpatrick_scale:false,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:'🐻',fitzpatrick_scale:false,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:'🐼',fitzpatrick_scale:false,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:'🐨',fitzpatrick_scale:false,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:'🐯',fitzpatrick_scale:false,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:'🦁',fitzpatrick_scale:false,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:'🐮',fitzpatrick_scale:false,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:'🐷',fitzpatrick_scale:false,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:'🐽',fitzpatrick_scale:false,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:'🐸',fitzpatrick_scale:false,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:'🦑',fitzpatrick_scale:false,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:'🐙',fitzpatrick_scale:false,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:'🦐',fitzpatrick_scale:false,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:'🐵',fitzpatrick_scale:false,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:'🦍',fitzpatrick_scale:false,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:'🙈',fitzpatrick_scale:false,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:'🙉',fitzpatrick_scale:false,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:'🙊',fitzpatrick_scale:false,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:'🐒',fitzpatrick_scale:false,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:'🐔',fitzpatrick_scale:false,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:'🐧',fitzpatrick_scale:false,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:'🐦',fitzpatrick_scale:false,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:'🐤',fitzpatrick_scale:false,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:'🐣',fitzpatrick_scale:false,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:'🐥',fitzpatrick_scale:false,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:'🦆',fitzpatrick_scale:false,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:'🦅',fitzpatrick_scale:false,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:'🦉',fitzpatrick_scale:false,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:'🦇',fitzpatrick_scale:false,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:'🐺',fitzpatrick_scale:false,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:'🐗',fitzpatrick_scale:false,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:'🐴',fitzpatrick_scale:false,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:'🦄',fitzpatrick_scale:false,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:'🐝',fitzpatrick_scale:false,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:'🐛',fitzpatrick_scale:false,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:'🦋',fitzpatrick_scale:false,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:'🐌',fitzpatrick_scale:false,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:'🐞',fitzpatrick_scale:false,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:'🐜',fitzpatrick_scale:false,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:'🦗',fitzpatrick_scale:false,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:'🕷',fitzpatrick_scale:false,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:'🦂',fitzpatrick_scale:false,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:'🦀',fitzpatrick_scale:false,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:'🐍',fitzpatrick_scale:false,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:'🦎',fitzpatrick_scale:false,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:'🦖',fitzpatrick_scale:false,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:'🦕',fitzpatrick_scale:false,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:'🐢',fitzpatrick_scale:false,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:'🐠',fitzpatrick_scale:false,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:'🐟',fitzpatrick_scale:false,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:'🐡',fitzpatrick_scale:false,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:'🐬',fitzpatrick_scale:false,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:'🦈',fitzpatrick_scale:false,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:'🐳',fitzpatrick_scale:false,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:'🐋',fitzpatrick_scale:false,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:'🐊',fitzpatrick_scale:false,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:'🐆',fitzpatrick_scale:false,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:'🦓',fitzpatrick_scale:false,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:'🐅',fitzpatrick_scale:false,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:'🐃',fitzpatrick_scale:false,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:'🐂',fitzpatrick_scale:false,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:'🐄',fitzpatrick_scale:false,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:'🦌',fitzpatrick_scale:false,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:'🐪',fitzpatrick_scale:false,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:'🐫',fitzpatrick_scale:false,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:'🦒',fitzpatrick_scale:false,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:'🐘',fitzpatrick_scale:false,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:'🦏',fitzpatrick_scale:false,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:'🐐',fitzpatrick_scale:false,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:'🐏',fitzpatrick_scale:false,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:'🐑',fitzpatrick_scale:false,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:'🐎',fitzpatrick_scale:false,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:'🐖',fitzpatrick_scale:false,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:'🐀',fitzpatrick_scale:false,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:'🐁',fitzpatrick_scale:false,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:'🐓',fitzpatrick_scale:false,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:'🦃',fitzpatrick_scale:false,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:'🕊',fitzpatrick_scale:false,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:'🐕',fitzpatrick_scale:false,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:'🐩',fitzpatrick_scale:false,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:'🐈',fitzpatrick_scale:false,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:'🐇',fitzpatrick_scale:false,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:'🐿',fitzpatrick_scale:false,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:'🦔',fitzpatrick_scale:false,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:'🦝',fitzpatrick_scale:false,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:'🦙',fitzpatrick_scale:false,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:'🦛',fitzpatrick_scale:false,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:'🦘',fitzpatrick_scale:false,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:'🦡',fitzpatrick_scale:false,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:'🦢',fitzpatrick_scale:false,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:'🦚',fitzpatrick_scale:false,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:'🦜',fitzpatrick_scale:false,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:'🦞',fitzpatrick_scale:false,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:'🦟',fitzpatrick_scale:false,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:'🐾',fitzpatrick_scale:false,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:'🐉',fitzpatrick_scale:false,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:'🐲',fitzpatrick_scale:false,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:'🌵',fitzpatrick_scale:false,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:'🎄',fitzpatrick_scale:false,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:'🌲',fitzpatrick_scale:false,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:'🌳',fitzpatrick_scale:false,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:'🌴',fitzpatrick_scale:false,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:'🌱',fitzpatrick_scale:false,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:'🌿',fitzpatrick_scale:false,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:'☘',fitzpatrick_scale:false,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:'🍀',fitzpatrick_scale:false,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:'🎍',fitzpatrick_scale:false,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:'🎋',fitzpatrick_scale:false,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:'🍃',fitzpatrick_scale:false,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:'🍂',fitzpatrick_scale:false,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:'🍁',fitzpatrick_scale:false,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:'🌾',fitzpatrick_scale:false,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:'🌺',fitzpatrick_scale:false,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:'🌻',fitzpatrick_scale:false,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:'🌹',fitzpatrick_scale:false,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:'🥀',fitzpatrick_scale:false,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:'🌷',fitzpatrick_scale:false,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:'🌼',fitzpatrick_scale:false,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:'🌸',fitzpatrick_scale:false,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:'💐',fitzpatrick_scale:false,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:'🍄',fitzpatrick_scale:false,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:'🌰',fitzpatrick_scale:false,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:'🎃',fitzpatrick_scale:false,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:'🐚',fitzpatrick_scale:false,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:'🕸',fitzpatrick_scale:false,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:'🌎',fitzpatrick_scale:false,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:'🌍',fitzpatrick_scale:false,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:'🌏',fitzpatrick_scale:false,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:'🌕',fitzpatrick_scale:false,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:'🌖',fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌗',fitzpatrick_scale:false,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌘',fitzpatrick_scale:false,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌑',fitzpatrick_scale:false,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌒',fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌓',fitzpatrick_scale:false,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:'🌔',fitzpatrick_scale:false,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌚',fitzpatrick_scale:false,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌝',fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌛',fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌜',fitzpatrick_scale:false,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:'🌞',fitzpatrick_scale:false,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:'🌙',fitzpatrick_scale:false,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:'⭐',fitzpatrick_scale:false,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:'🌟',fitzpatrick_scale:false,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:'💫',fitzpatrick_scale:false,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:'✨',fitzpatrick_scale:false,category:"animals_and_nature"},comet:{keywords:["space"],char:'☄',fitzpatrick_scale:false,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:'☀️',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:'🌤',fitzpatrick_scale:false,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:'⛅',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:'🌥',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:'🌦',fitzpatrick_scale:false,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:'☁️',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:'🌧',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:'⛈',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:'🌩',fitzpatrick_scale:false,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:'⚡',fitzpatrick_scale:false,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:'🔥',fitzpatrick_scale:false,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:'💥',fitzpatrick_scale:false,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:'❄️',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:'🌨',fitzpatrick_scale:false,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:'⛄',fitzpatrick_scale:false,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:'☃',fitzpatrick_scale:false,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:'🌬',fitzpatrick_scale:false,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:'💨',fitzpatrick_scale:false,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:'🌪',fitzpatrick_scale:false,category:"animals_and_nature"},fog:{keywords:["weather"],char:'🌫',fitzpatrick_scale:false,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:'☂',fitzpatrick_scale:false,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:'☔',fitzpatrick_scale:false,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:'💧',fitzpatrick_scale:false,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:'💦',fitzpatrick_scale:false,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:'🌊',fitzpatrick_scale:false,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:'🍏',fitzpatrick_scale:false,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:'🍎',fitzpatrick_scale:false,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:'🍐',fitzpatrick_scale:false,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:'🍊',fitzpatrick_scale:false,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:'🍋',fitzpatrick_scale:false,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:'🍌',fitzpatrick_scale:false,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:'🍉',fitzpatrick_scale:false,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:'🍇',fitzpatrick_scale:false,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:'🍓',fitzpatrick_scale:false,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:'🍈',fitzpatrick_scale:false,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:'🍒',fitzpatrick_scale:false,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:'🍑',fitzpatrick_scale:false,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:'🍍',fitzpatrick_scale:false,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:'🥥',fitzpatrick_scale:false,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:'🥝',fitzpatrick_scale:false,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:'🥭',fitzpatrick_scale:false,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:'🥑',fitzpatrick_scale:false,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:'🥦',fitzpatrick_scale:false,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:'🍅',fitzpatrick_scale:false,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:'🍆',fitzpatrick_scale:false,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:'🥒',fitzpatrick_scale:false,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:'🥕',fitzpatrick_scale:false,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:'🌶',fitzpatrick_scale:false,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:'🥔',fitzpatrick_scale:false,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:'🌽',fitzpatrick_scale:false,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:'🥬',fitzpatrick_scale:false,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:'🍠',fitzpatrick_scale:false,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:'🥜',fitzpatrick_scale:false,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:'🍯',fitzpatrick_scale:false,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:'🥐',fitzpatrick_scale:false,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:'🍞',fitzpatrick_scale:false,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:'🥖',fitzpatrick_scale:false,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:'🥯',fitzpatrick_scale:false,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:'🥨',fitzpatrick_scale:false,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:'🧀',fitzpatrick_scale:false,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:'🥚',fitzpatrick_scale:false,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:'🥓',fitzpatrick_scale:false,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:'🥩',fitzpatrick_scale:false,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:'🥞',fitzpatrick_scale:false,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:'🍗',fitzpatrick_scale:false,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:'🍖',fitzpatrick_scale:false,category:"food_and_drink"},bone:{keywords:["skeleton"],char:'🦴',fitzpatrick_scale:false,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:'🍤',fitzpatrick_scale:false,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:'🍳',fitzpatrick_scale:false,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:'🍔',fitzpatrick_scale:false,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:'🍟',fitzpatrick_scale:false,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:'🥙',fitzpatrick_scale:false,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:'🌭',fitzpatrick_scale:false,category:"food_and_drink"},pizza:{keywords:["food","party"],char:'🍕',fitzpatrick_scale:false,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:'🥪',fitzpatrick_scale:false,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:'🥫',fitzpatrick_scale:false,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:'🍝',fitzpatrick_scale:false,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:'🌮',fitzpatrick_scale:false,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:'🌯',fitzpatrick_scale:false,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:'🥗',fitzpatrick_scale:false,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:'🥘',fitzpatrick_scale:false,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:'🍜',fitzpatrick_scale:false,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:'🍲',fitzpatrick_scale:false,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:'🍥',fitzpatrick_scale:false,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:'🥠',fitzpatrick_scale:false,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:'🍣',fitzpatrick_scale:false,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:'🍱',fitzpatrick_scale:false,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:'🍛',fitzpatrick_scale:false,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:'🍙',fitzpatrick_scale:false,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:'🍚',fitzpatrick_scale:false,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:'🍘',fitzpatrick_scale:false,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:'🍢',fitzpatrick_scale:false,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:'🍡',fitzpatrick_scale:false,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:'🍧',fitzpatrick_scale:false,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:'🍨',fitzpatrick_scale:false,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:'🍦',fitzpatrick_scale:false,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:'🥧',fitzpatrick_scale:false,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:'🍰',fitzpatrick_scale:false,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:'🧁',fitzpatrick_scale:false,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:'🥮',fitzpatrick_scale:false,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:'🎂',fitzpatrick_scale:false,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:'🍮',fitzpatrick_scale:false,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:'🍬',fitzpatrick_scale:false,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:'🍭',fitzpatrick_scale:false,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:'🍫',fitzpatrick_scale:false,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:'🍿',fitzpatrick_scale:false,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:'🥟',fitzpatrick_scale:false,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:'🍩',fitzpatrick_scale:false,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:'🍪',fitzpatrick_scale:false,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:'🥛',fitzpatrick_scale:false,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'🍺',fitzpatrick_scale:false,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'🍻',fitzpatrick_scale:false,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:'🥂',fitzpatrick_scale:false,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:'🍷',fitzpatrick_scale:false,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:'🥃',fitzpatrick_scale:false,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:'🍸',fitzpatrick_scale:false,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:'🍹',fitzpatrick_scale:false,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:'🍾',fitzpatrick_scale:false,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:'🍶',fitzpatrick_scale:false,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:'🍵',fitzpatrick_scale:false,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:'🥤',fitzpatrick_scale:false,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:'☕',fitzpatrick_scale:false,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:'🍼',fitzpatrick_scale:false,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:'🧂',fitzpatrick_scale:false,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:'🥄',fitzpatrick_scale:false,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:'🍴',fitzpatrick_scale:false,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:'🍽',fitzpatrick_scale:false,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:'🥣',fitzpatrick_scale:false,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:'🥡',fitzpatrick_scale:false,category:"food_and_drink"},chopsticks:{keywords:["food"],char:'🥢',fitzpatrick_scale:false,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:'⚽',fitzpatrick_scale:false,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:'🏀',fitzpatrick_scale:false,category:"activity"},football:{keywords:["sports","balls","NFL"],char:'🏈',fitzpatrick_scale:false,category:"activity"},baseball:{keywords:["sports","balls"],char:'⚾',fitzpatrick_scale:false,category:"activity"},softball:{keywords:["sports","balls"],char:'🥎',fitzpatrick_scale:false,category:"activity"},tennis:{keywords:["sports","balls","green"],char:'🎾',fitzpatrick_scale:false,category:"activity"},volleyball:{keywords:["sports","balls"],char:'🏐',fitzpatrick_scale:false,category:"activity"},rugby_football:{keywords:["sports","team"],char:'🏉',fitzpatrick_scale:false,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:'🥏',fitzpatrick_scale:false,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:'🎱',fitzpatrick_scale:false,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:'⛳',fitzpatrick_scale:false,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:'🏌️‍♀️',fitzpatrick_scale:false,category:"activity"},golfing_man:{keywords:["sports","business"],char:'🏌',fitzpatrick_scale:true,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:'🏓',fitzpatrick_scale:false,category:"activity"},badminton:{keywords:["sports"],char:'🏸',fitzpatrick_scale:false,category:"activity"},goal_net:{keywords:["sports"],char:'🥅',fitzpatrick_scale:false,category:"activity"},ice_hockey:{keywords:["sports"],char:'🏒',fitzpatrick_scale:false,category:"activity"},field_hockey:{keywords:["sports"],char:'🏑',fitzpatrick_scale:false,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:'🥍',fitzpatrick_scale:false,category:"activity"},cricket:{keywords:["sports"],char:'🏏',fitzpatrick_scale:false,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:'🎿',fitzpatrick_scale:false,category:"activity"},skier:{keywords:["sports","winter","snow"],char:'⛷',fitzpatrick_scale:false,category:"activity"},snowboarder:{keywords:["sports","winter"],char:'🏂',fitzpatrick_scale:true,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:'🤺',fitzpatrick_scale:false,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:'🤼‍♀️',fitzpatrick_scale:false,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:'🤼‍♂️',fitzpatrick_scale:false,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:'🤸‍♀️',fitzpatrick_scale:true,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:'🤸‍♂️',fitzpatrick_scale:true,category:"activity"},woman_playing_handball:{keywords:["sports"],char:'🤾‍♀️',fitzpatrick_scale:true,category:"activity"},man_playing_handball:{keywords:["sports"],char:'🤾‍♂️',fitzpatrick_scale:true,category:"activity"},ice_skate:{keywords:["sports"],char:'⛸',fitzpatrick_scale:false,category:"activity"},curling_stone:{keywords:["sports"],char:'🥌',fitzpatrick_scale:false,category:"activity"},skateboard:{keywords:["board"],char:'🛹',fitzpatrick_scale:false,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:'🛷',fitzpatrick_scale:false,category:"activity"},bow_and_arrow:{keywords:["sports"],char:'🏹',fitzpatrick_scale:false,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:'🎣',fitzpatrick_scale:false,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:'🥊',fitzpatrick_scale:false,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:'🥋',fitzpatrick_scale:false,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:'🚣‍♀️',fitzpatrick_scale:true,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:'🚣',fitzpatrick_scale:true,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:'🧗‍♀️',fitzpatrick_scale:true,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:'🧗‍♂️',fitzpatrick_scale:true,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:'🏊‍♀️',fitzpatrick_scale:true,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:'🏊',fitzpatrick_scale:true,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:'🤽‍♀️',fitzpatrick_scale:true,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:'🤽‍♂️',fitzpatrick_scale:true,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:'🧘‍♀️',fitzpatrick_scale:true,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:'🧘‍♂️',fitzpatrick_scale:true,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:'🏄‍♀️',fitzpatrick_scale:true,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:'🏄',fitzpatrick_scale:true,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:'🛀',fitzpatrick_scale:true,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:'⛹️‍♀️',fitzpatrick_scale:true,category:"activity"},basketball_man:{keywords:["sports","human"],char:'⛹',fitzpatrick_scale:true,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:'🏋️‍♀️',fitzpatrick_scale:true,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:'🏋',fitzpatrick_scale:true,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:'🚴‍♀️',fitzpatrick_scale:true,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:'🚴',fitzpatrick_scale:true,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:'🚵‍♀️',fitzpatrick_scale:true,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:'🚵',fitzpatrick_scale:true,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:'🏇',fitzpatrick_scale:true,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:'🕴',fitzpatrick_scale:true,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:'🏆',fitzpatrick_scale:false,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:'🎽',fitzpatrick_scale:false,category:"activity"},medal_sports:{keywords:["award","winning"],char:'🏅',fitzpatrick_scale:false,category:"activity"},medal_military:{keywords:["award","winning","army"],char:'🎖',fitzpatrick_scale:false,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:'🥇',fitzpatrick_scale:false,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:'🥈',fitzpatrick_scale:false,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:'🥉',fitzpatrick_scale:false,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:'🎗',fitzpatrick_scale:false,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:'🏵',fitzpatrick_scale:false,category:"activity"},ticket:{keywords:["event","concert","pass"],char:'🎫',fitzpatrick_scale:false,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:'🎟',fitzpatrick_scale:false,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:'🎭',fitzpatrick_scale:false,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:'🎨',fitzpatrick_scale:false,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:'🎪',fitzpatrick_scale:false,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:'🤹‍♀️',fitzpatrick_scale:true,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:'🤹‍♂️',fitzpatrick_scale:true,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:'🎤',fitzpatrick_scale:false,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:'🎧',fitzpatrick_scale:false,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:'🎼',fitzpatrick_scale:false,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:'🎹',fitzpatrick_scale:false,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:'🥁',fitzpatrick_scale:false,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:'🎷',fitzpatrick_scale:false,category:"activity"},trumpet:{keywords:["music","brass"],char:'🎺',fitzpatrick_scale:false,category:"activity"},guitar:{keywords:["music","instrument"],char:'🎸',fitzpatrick_scale:false,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:'🎻',fitzpatrick_scale:false,category:"activity"},clapper:{keywords:["movie","film","record"],char:'🎬',fitzpatrick_scale:false,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:'🎮',fitzpatrick_scale:false,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:'👾',fitzpatrick_scale:false,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:'🎯',fitzpatrick_scale:false,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:'🎲',fitzpatrick_scale:false,category:"activity"},chess_pawn:{keywords:["expendable"],char:"♟",fitzpatrick_scale:false,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:'🎰',fitzpatrick_scale:false,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:'🧩',fitzpatrick_scale:false,category:"activity"},bowling:{keywords:["sports","fun","play"],char:'🎳',fitzpatrick_scale:false,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:'🚗',fitzpatrick_scale:false,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:'🚕',fitzpatrick_scale:false,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:'🚙',fitzpatrick_scale:false,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:'🚌',fitzpatrick_scale:false,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:'🚎',fitzpatrick_scale:false,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:'🏎',fitzpatrick_scale:false,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:'🚓',fitzpatrick_scale:false,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:'🚑',fitzpatrick_scale:false,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:'🚒',fitzpatrick_scale:false,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:'🚐',fitzpatrick_scale:false,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:'🚚',fitzpatrick_scale:false,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:'🚛',fitzpatrick_scale:false,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:'🚜',fitzpatrick_scale:false,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:'🛴',fitzpatrick_scale:false,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:'🏍',fitzpatrick_scale:false,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:'🚲',fitzpatrick_scale:false,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:'🛵',fitzpatrick_scale:false,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:'🚨',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:'🚔',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:'🚍',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:'🚘',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:'🚖',fitzpatrick_scale:false,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:'🚡',fitzpatrick_scale:false,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:'🚠',fitzpatrick_scale:false,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:'🚟',fitzpatrick_scale:false,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:'🚃',fitzpatrick_scale:false,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:'🚋',fitzpatrick_scale:false,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:'🚝',fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:'🚄',fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:'🚅',fitzpatrick_scale:false,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:'🚈',fitzpatrick_scale:false,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:'🚞',fitzpatrick_scale:false,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:'🚂',fitzpatrick_scale:false,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:'🚆',fitzpatrick_scale:false,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:'🚇',fitzpatrick_scale:false,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:'🚊',fitzpatrick_scale:false,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:'🚉',fitzpatrick_scale:false,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:'🛸',fitzpatrick_scale:false,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:'🚁',fitzpatrick_scale:false,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:'🛩',fitzpatrick_scale:false,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:'✈️',fitzpatrick_scale:false,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:'🛫',fitzpatrick_scale:false,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:'🛬',fitzpatrick_scale:false,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:'⛵',fitzpatrick_scale:false,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:'🛥',fitzpatrick_scale:false,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:'🚤',fitzpatrick_scale:false,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:'⛴',fitzpatrick_scale:false,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:'🛳',fitzpatrick_scale:false,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:'🚀',fitzpatrick_scale:false,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:'🛰',fitzpatrick_scale:false,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:'💺',fitzpatrick_scale:false,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:'🛶',fitzpatrick_scale:false,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:'⚓',fitzpatrick_scale:false,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:'🚧',fitzpatrick_scale:false,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:'⛽',fitzpatrick_scale:false,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:'🚏',fitzpatrick_scale:false,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:'🚦',fitzpatrick_scale:false,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:'🚥',fitzpatrick_scale:false,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:'🏁',fitzpatrick_scale:false,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:'🚢',fitzpatrick_scale:false,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:'🎡',fitzpatrick_scale:false,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:'🎢',fitzpatrick_scale:false,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:'🎠',fitzpatrick_scale:false,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:'🏗',fitzpatrick_scale:false,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:'🌁',fitzpatrick_scale:false,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:'🗼',fitzpatrick_scale:false,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:'🏭',fitzpatrick_scale:false,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:'⛲',fitzpatrick_scale:false,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:'🎑',fitzpatrick_scale:false,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:'⛰',fitzpatrick_scale:false,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:'🏔',fitzpatrick_scale:false,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:'🗻',fitzpatrick_scale:false,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:'🌋',fitzpatrick_scale:false,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:'🗾',fitzpatrick_scale:false,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:'🏕',fitzpatrick_scale:false,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:'⛺',fitzpatrick_scale:false,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:'🏞',fitzpatrick_scale:false,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:'🛣',fitzpatrick_scale:false,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:'🛤',fitzpatrick_scale:false,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:'🌅',fitzpatrick_scale:false,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:'🌄',fitzpatrick_scale:false,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:'🏜',fitzpatrick_scale:false,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:'🏖',fitzpatrick_scale:false,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:'🏝',fitzpatrick_scale:false,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:'🌇',fitzpatrick_scale:false,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:'🌆',fitzpatrick_scale:false,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:'🏙',fitzpatrick_scale:false,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:'🌃',fitzpatrick_scale:false,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:'🌉',fitzpatrick_scale:false,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:'🌌',fitzpatrick_scale:false,category:"travel_and_places"},stars:{keywords:["night","photo"],char:'🌠',fitzpatrick_scale:false,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:'🎇',fitzpatrick_scale:false,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:'🎆',fitzpatrick_scale:false,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:'🌈',fitzpatrick_scale:false,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:'🏘',fitzpatrick_scale:false,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:'🏰',fitzpatrick_scale:false,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:'🏯',fitzpatrick_scale:false,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:'🏟',fitzpatrick_scale:false,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:'🗽',fitzpatrick_scale:false,category:"travel_and_places"},house:{keywords:["building","home"],char:'🏠',fitzpatrick_scale:false,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:'🏡',fitzpatrick_scale:false,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:'🏚',fitzpatrick_scale:false,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:'🏢',fitzpatrick_scale:false,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:'🏬',fitzpatrick_scale:false,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:'🏣',fitzpatrick_scale:false,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:'🏤',fitzpatrick_scale:false,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:'🏥',fitzpatrick_scale:false,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:'🏦',fitzpatrick_scale:false,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:'🏨',fitzpatrick_scale:false,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:'🏪',fitzpatrick_scale:false,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:'🏫',fitzpatrick_scale:false,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:'🏩',fitzpatrick_scale:false,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:'💒',fitzpatrick_scale:false,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:'🏛',fitzpatrick_scale:false,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:'⛪',fitzpatrick_scale:false,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:'🕌',fitzpatrick_scale:false,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:'🕍',fitzpatrick_scale:false,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:'🕋',fitzpatrick_scale:false,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:'⛩',fitzpatrick_scale:false,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:'⌚',fitzpatrick_scale:false,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:'📱',fitzpatrick_scale:false,category:"objects"},calling:{keywords:["iphone","incoming"],char:'📲',fitzpatrick_scale:false,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:'💻',fitzpatrick_scale:false,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:'⌨',fitzpatrick_scale:false,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:'🖥',fitzpatrick_scale:false,category:"objects"},printer:{keywords:["paper","ink"],char:'🖨',fitzpatrick_scale:false,category:"objects"},computer_mouse:{keywords:["click"],char:'🖱',fitzpatrick_scale:false,category:"objects"},trackball:{keywords:["technology","trackpad"],char:'🖲',fitzpatrick_scale:false,category:"objects"},joystick:{keywords:["game","play"],char:'🕹',fitzpatrick_scale:false,category:"objects"},clamp:{keywords:["tool"],char:'🗜',fitzpatrick_scale:false,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:'💽',fitzpatrick_scale:false,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:'💾',fitzpatrick_scale:false,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:'💿',fitzpatrick_scale:false,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:'📀',fitzpatrick_scale:false,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:'📼',fitzpatrick_scale:false,category:"objects"},camera:{keywords:["gadgets","photography"],char:'📷',fitzpatrick_scale:false,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:'📸',fitzpatrick_scale:false,category:"objects"},video_camera:{keywords:["film","record"],char:'📹',fitzpatrick_scale:false,category:"objects"},movie_camera:{keywords:["film","record"],char:'🎥',fitzpatrick_scale:false,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:'📽',fitzpatrick_scale:false,category:"objects"},film_strip:{keywords:["movie"],char:'🎞',fitzpatrick_scale:false,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:'📞',fitzpatrick_scale:false,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:'☎️',fitzpatrick_scale:false,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:'📟',fitzpatrick_scale:false,category:"objects"},fax:{keywords:["communication","technology"],char:'📠',fitzpatrick_scale:false,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:'📺',fitzpatrick_scale:false,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:'📻',fitzpatrick_scale:false,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:'🎙',fitzpatrick_scale:false,category:"objects"},level_slider:{keywords:["scale"],char:'🎚',fitzpatrick_scale:false,category:"objects"},control_knobs:{keywords:["dial"],char:'🎛',fitzpatrick_scale:false,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:'🧭',fitzpatrick_scale:false,category:"objects"},stopwatch:{keywords:["time","deadline"],char:'⏱',fitzpatrick_scale:false,category:"objects"},timer_clock:{keywords:["alarm"],char:'⏲',fitzpatrick_scale:false,category:"objects"},alarm_clock:{keywords:["time","wake"],char:'⏰',fitzpatrick_scale:false,category:"objects"},mantelpiece_clock:{keywords:["time"],char:'🕰',fitzpatrick_scale:false,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:'⏳',fitzpatrick_scale:false,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:'⌛',fitzpatrick_scale:false,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:'📡',fitzpatrick_scale:false,category:"objects"},battery:{keywords:["power","energy","sustain"],char:'🔋',fitzpatrick_scale:false,category:"objects"},electric_plug:{keywords:["charger","power"],char:'🔌',fitzpatrick_scale:false,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:'💡',fitzpatrick_scale:false,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:'🔦',fitzpatrick_scale:false,category:"objects"},candle:{keywords:["fire","wax"],char:'🕯',fitzpatrick_scale:false,category:"objects"},fire_extinguisher:{keywords:["quench"],char:'🧯',fitzpatrick_scale:false,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:'🗑',fitzpatrick_scale:false,category:"objects"},oil_drum:{keywords:["barrell"],char:'🛢',fitzpatrick_scale:false,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:'💸',fitzpatrick_scale:false,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:'💵',fitzpatrick_scale:false,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:'💴',fitzpatrick_scale:false,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:'💶',fitzpatrick_scale:false,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:'💷',fitzpatrick_scale:false,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:'💰',fitzpatrick_scale:false,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:'💳',fitzpatrick_scale:false,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:'💎',fitzpatrick_scale:false,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:'⚖',fitzpatrick_scale:false,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:'🧰',fitzpatrick_scale:false,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:'🔧',fitzpatrick_scale:false,category:"objects"},hammer:{keywords:["tools","build","create"],char:'🔨',fitzpatrick_scale:false,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:'⚒',fitzpatrick_scale:false,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:'🛠',fitzpatrick_scale:false,category:"objects"},pick:{keywords:["tools","dig"],char:'⛏',fitzpatrick_scale:false,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:'🔩',fitzpatrick_scale:false,category:"objects"},gear:{keywords:["cog"],char:'⚙',fitzpatrick_scale:false,category:"objects"},brick:{keywords:["bricks"],char:'🧱',fitzpatrick_scale:false,category:"objects"},chains:{keywords:["lock","arrest"],char:'⛓',fitzpatrick_scale:false,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:'🧲',fitzpatrick_scale:false,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:'🔫',fitzpatrick_scale:false,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:'💣',fitzpatrick_scale:false,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:'🧨',fitzpatrick_scale:false,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:'🔪',fitzpatrick_scale:false,category:"objects"},dagger:{keywords:["weapon"],char:'🗡',fitzpatrick_scale:false,category:"objects"},crossed_swords:{keywords:["weapon"],char:'⚔',fitzpatrick_scale:false,category:"objects"},shield:{keywords:["protection","security"],char:'🛡',fitzpatrick_scale:false,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:'🚬',fitzpatrick_scale:false,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:'☠',fitzpatrick_scale:false,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:'⚰',fitzpatrick_scale:false,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:'⚱',fitzpatrick_scale:false,category:"objects"},amphora:{keywords:["vase","jar"],char:'🏺',fitzpatrick_scale:false,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:'🔮',fitzpatrick_scale:false,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:'📿',fitzpatrick_scale:false,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:'🧿',fitzpatrick_scale:false,category:"objects"},barber:{keywords:["hair","salon","style"],char:'💈',fitzpatrick_scale:false,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:'⚗',fitzpatrick_scale:false,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:'🔭',fitzpatrick_scale:false,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:'🔬',fitzpatrick_scale:false,category:"objects"},hole:{keywords:["embarrassing"],char:'🕳',fitzpatrick_scale:false,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:'💊',fitzpatrick_scale:false,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:'💉',fitzpatrick_scale:false,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:'🧬',fitzpatrick_scale:false,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:'🦠',fitzpatrick_scale:false,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:'🧫',fitzpatrick_scale:false,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:'🧪',fitzpatrick_scale:false,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:'🌡',fitzpatrick_scale:false,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:'🧹',fitzpatrick_scale:false,category:"objects"},basket:{keywords:["laundry"],char:'🧺',fitzpatrick_scale:false,category:"objects"},toilet_paper:{keywords:["roll"],char:'🧻',fitzpatrick_scale:false,category:"objects"},label:{keywords:["sale","tag"],char:'🏷',fitzpatrick_scale:false,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:'🔖',fitzpatrick_scale:false,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:'🚽',fitzpatrick_scale:false,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:'🚿',fitzpatrick_scale:false,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:'🛁',fitzpatrick_scale:false,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:'🧼',fitzpatrick_scale:false,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:'🧽',fitzpatrick_scale:false,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:'🧴',fitzpatrick_scale:false,category:"objects"},key:{keywords:["lock","door","password"],char:'🔑',fitzpatrick_scale:false,category:"objects"},old_key:{keywords:["lock","door","password"],char:'🗝',fitzpatrick_scale:false,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:'🛋',fitzpatrick_scale:false,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:'🛌',fitzpatrick_scale:true,category:"objects"},bed:{keywords:["sleep","rest"],char:'🛏',fitzpatrick_scale:false,category:"objects"},door:{keywords:["house","entry","exit"],char:'🚪',fitzpatrick_scale:false,category:"objects"},bellhop_bell:{keywords:["service"],char:'🛎',fitzpatrick_scale:false,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:'🧸',fitzpatrick_scale:false,category:"objects"},framed_picture:{keywords:["photography"],char:'🖼',fitzpatrick_scale:false,category:"objects"},world_map:{keywords:["location","direction"],char:'🗺',fitzpatrick_scale:false,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:'⛱',fitzpatrick_scale:false,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:'🗿',fitzpatrick_scale:false,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:'🛍',fitzpatrick_scale:false,category:"objects"},shopping_cart:{keywords:["trolley"],char:'🛒',fitzpatrick_scale:false,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:'🎈',fitzpatrick_scale:false,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:'🎏',fitzpatrick_scale:false,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:'🎀',fitzpatrick_scale:false,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:'🎁',fitzpatrick_scale:false,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:'🎊',fitzpatrick_scale:false,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:'🎉',fitzpatrick_scale:false,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:'🎎',fitzpatrick_scale:false,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:'🎐',fitzpatrick_scale:false,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:'🎌',fitzpatrick_scale:false,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:'🏮',fitzpatrick_scale:false,category:"objects"},red_envelope:{keywords:["gift"],char:'🧧',fitzpatrick_scale:false,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:'✉️',fitzpatrick_scale:false,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:'📩',fitzpatrick_scale:false,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:'📨',fitzpatrick_scale:false,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:'📧',fitzpatrick_scale:false,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:'💌',fitzpatrick_scale:false,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:'📮',fitzpatrick_scale:false,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:'📪',fitzpatrick_scale:false,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:'📫',fitzpatrick_scale:false,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:'📬',fitzpatrick_scale:false,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:'📭',fitzpatrick_scale:false,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:'📦',fitzpatrick_scale:false,category:"objects"},postal_horn:{keywords:["instrument","music"],char:'📯',fitzpatrick_scale:false,category:"objects"},inbox_tray:{keywords:["email","documents"],char:'📥',fitzpatrick_scale:false,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:'📤',fitzpatrick_scale:false,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:'📜',fitzpatrick_scale:false,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:'📃',fitzpatrick_scale:false,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:'📑',fitzpatrick_scale:false,category:"objects"},receipt:{keywords:["accounting","expenses"],char:'🧾',fitzpatrick_scale:false,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:'📊',fitzpatrick_scale:false,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:'📈',fitzpatrick_scale:false,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:'📉',fitzpatrick_scale:false,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:'📄',fitzpatrick_scale:false,category:"objects"},date:{keywords:["calendar","schedule"],char:'📅',fitzpatrick_scale:false,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:'📆',fitzpatrick_scale:false,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:'🗓',fitzpatrick_scale:false,category:"objects"},card_index:{keywords:["business","stationery"],char:'📇',fitzpatrick_scale:false,category:"objects"},card_file_box:{keywords:["business","stationery"],char:'🗃',fitzpatrick_scale:false,category:"objects"},ballot_box:{keywords:["election","vote"],char:'🗳',fitzpatrick_scale:false,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:'🗄',fitzpatrick_scale:false,category:"objects"},clipboard:{keywords:["stationery","documents"],char:'📋',fitzpatrick_scale:false,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:'🗒',fitzpatrick_scale:false,category:"objects"},file_folder:{keywords:["documents","business","office"],char:'📁',fitzpatrick_scale:false,category:"objects"},open_file_folder:{keywords:["documents","load"],char:'📂',fitzpatrick_scale:false,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:'🗂',fitzpatrick_scale:false,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:'🗞',fitzpatrick_scale:false,category:"objects"},newspaper:{keywords:["press","headline"],char:'📰',fitzpatrick_scale:false,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:'📓',fitzpatrick_scale:false,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:'📕',fitzpatrick_scale:false,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:'📗',fitzpatrick_scale:false,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:'📘',fitzpatrick_scale:false,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:'📙',fitzpatrick_scale:false,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:'📔',fitzpatrick_scale:false,category:"objects"},ledger:{keywords:["notes","paper"],char:'📒',fitzpatrick_scale:false,category:"objects"},books:{keywords:["literature","library","study"],char:'📚',fitzpatrick_scale:false,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:'📖',fitzpatrick_scale:false,category:"objects"},safety_pin:{keywords:["diaper"],char:'🧷',fitzpatrick_scale:false,category:"objects"},link:{keywords:["rings","url"],char:'🔗',fitzpatrick_scale:false,category:"objects"},paperclip:{keywords:["documents","stationery"],char:'📎',fitzpatrick_scale:false,category:"objects"},paperclips:{keywords:["documents","stationery"],char:'🖇',fitzpatrick_scale:false,category:"objects"},scissors:{keywords:["stationery","cut"],char:'✂️',fitzpatrick_scale:false,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:'📐',fitzpatrick_scale:false,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:'📏',fitzpatrick_scale:false,category:"objects"},abacus:{keywords:["calculation"],char:'🧮',fitzpatrick_scale:false,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:'📌',fitzpatrick_scale:false,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:'📍',fitzpatrick_scale:false,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:'🚩',fitzpatrick_scale:false,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:'🏳',fitzpatrick_scale:false,category:"objects"},black_flag:{keywords:["pirate"],char:'🏴',fitzpatrick_scale:false,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:'🏳️‍🌈',fitzpatrick_scale:false,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:'🔐',fitzpatrick_scale:false,category:"objects"},lock:{keywords:["security","password","padlock"],char:'🔒',fitzpatrick_scale:false,category:"objects"},unlock:{keywords:["privacy","security"],char:'🔓',fitzpatrick_scale:false,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:'🔏',fitzpatrick_scale:false,category:"objects"},pen:{keywords:["stationery","writing","write"],char:'🖊',fitzpatrick_scale:false,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:'🖋',fitzpatrick_scale:false,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:'✒️',fitzpatrick_scale:false,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:'📝',fitzpatrick_scale:false,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:'✏️',fitzpatrick_scale:false,category:"objects"},crayon:{keywords:["drawing","creativity"],char:'🖍',fitzpatrick_scale:false,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:'🖌',fitzpatrick_scale:false,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:'🔍',fitzpatrick_scale:false,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:'🔎',fitzpatrick_scale:false,category:"objects"},heart:{keywords:["love","like","valentines"],char:'❤️',fitzpatrick_scale:false,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:'🧡',fitzpatrick_scale:false,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:'💛',fitzpatrick_scale:false,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:'💚',fitzpatrick_scale:false,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:'💙',fitzpatrick_scale:false,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:'💜',fitzpatrick_scale:false,category:"symbols"},black_heart:{keywords:["evil"],char:'🖤',fitzpatrick_scale:false,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:'💔',fitzpatrick_scale:false,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:'❣',fitzpatrick_scale:false,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:'💕',fitzpatrick_scale:false,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:'💞',fitzpatrick_scale:false,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:'💓',fitzpatrick_scale:false,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:'💗',fitzpatrick_scale:false,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:'💖',fitzpatrick_scale:false,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:'💘',fitzpatrick_scale:false,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:'💝',fitzpatrick_scale:false,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:'💟',fitzpatrick_scale:false,category:"symbols"},peace_symbol:{keywords:["hippie"],char:'☮',fitzpatrick_scale:false,category:"symbols"},latin_cross:{keywords:["christianity"],char:'✝',fitzpatrick_scale:false,category:"symbols"},star_and_crescent:{keywords:["islam"],char:'☪',fitzpatrick_scale:false,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'🕉',fitzpatrick_scale:false,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'☸',fitzpatrick_scale:false,category:"symbols"},star_of_david:{keywords:["judaism"],char:'✡',fitzpatrick_scale:false,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:'🔯',fitzpatrick_scale:false,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:'🕎',fitzpatrick_scale:false,category:"symbols"},yin_yang:{keywords:["balance"],char:'☯',fitzpatrick_scale:false,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:'☦',fitzpatrick_scale:false,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:'🛐',fitzpatrick_scale:false,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:'⛎',fitzpatrick_scale:false,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:'♈',fitzpatrick_scale:false,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:'♉',fitzpatrick_scale:false,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:'♊',fitzpatrick_scale:false,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:'♋',fitzpatrick_scale:false,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:'♌',fitzpatrick_scale:false,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:'♍',fitzpatrick_scale:false,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:'♎',fitzpatrick_scale:false,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:'♏',fitzpatrick_scale:false,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:'♐',fitzpatrick_scale:false,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:'♑',fitzpatrick_scale:false,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:'♒',fitzpatrick_scale:false,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:'♓',fitzpatrick_scale:false,category:"symbols"},id:{keywords:["purple-square","words"],char:'🆔',fitzpatrick_scale:false,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:'⚛',fitzpatrick_scale:false,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:'🈳',fitzpatrick_scale:false,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:'🈹',fitzpatrick_scale:false,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:'☢',fitzpatrick_scale:false,category:"symbols"},biohazard:{keywords:["danger"],char:'☣',fitzpatrick_scale:false,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:'📴',fitzpatrick_scale:false,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:'📳',fitzpatrick_scale:false,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:'🈶',fitzpatrick_scale:false,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:'🈚',fitzpatrick_scale:false,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:'🈸',fitzpatrick_scale:false,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:'🈺',fitzpatrick_scale:false,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:'🈷️',fitzpatrick_scale:false,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:'✴️',fitzpatrick_scale:false,category:"symbols"},vs:{keywords:["words","orange-square"],char:'🆚',fitzpatrick_scale:false,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:'🉑',fitzpatrick_scale:false,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:'💮',fitzpatrick_scale:false,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:'🉐',fitzpatrick_scale:false,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:'㊙️',fitzpatrick_scale:false,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:'㊗️',fitzpatrick_scale:false,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:'🈴',fitzpatrick_scale:false,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:'🈵',fitzpatrick_scale:false,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:'🈲',fitzpatrick_scale:false,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:'🅰️',fitzpatrick_scale:false,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:'🅱️',fitzpatrick_scale:false,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:'🆎',fitzpatrick_scale:false,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:'🆑',fitzpatrick_scale:false,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:'🅾️',fitzpatrick_scale:false,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:'🆘',fitzpatrick_scale:false,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:'⛔',fitzpatrick_scale:false,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:'📛',fitzpatrick_scale:false,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:'🚫',fitzpatrick_scale:false,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:'❌',fitzpatrick_scale:false,category:"symbols"},o:{keywords:["circle","round"],char:'⭕',fitzpatrick_scale:false,category:"symbols"},stop_sign:{keywords:["stop"],char:'🛑',fitzpatrick_scale:false,category:"symbols"},anger:{keywords:["angry","mad"],char:'💢',fitzpatrick_scale:false,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:'♨️',fitzpatrick_scale:false,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:'🚷',fitzpatrick_scale:false,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:'🚯',fitzpatrick_scale:false,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:'🚳',fitzpatrick_scale:false,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:'🚱',fitzpatrick_scale:false,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:'🔞',fitzpatrick_scale:false,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:'📵',fitzpatrick_scale:false,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:'❗',fitzpatrick_scale:false,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:'❕',fitzpatrick_scale:false,category:"symbols"},question:{keywords:["doubt","confused"],char:'❓',fitzpatrick_scale:false,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:'❔',fitzpatrick_scale:false,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:'‼️',fitzpatrick_scale:false,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:'⁉️',fitzpatrick_scale:false,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:'🔅',fitzpatrick_scale:false,category:"symbols"},high_brightness:{keywords:["sun","light"],char:'🔆',fitzpatrick_scale:false,category:"symbols"},trident:{keywords:["weapon","spear"],char:'🔱',fitzpatrick_scale:false,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:'⚜',fitzpatrick_scale:false,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:'〽️',fitzpatrick_scale:false,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:'⚠️',fitzpatrick_scale:false,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:'🚸',fitzpatrick_scale:false,category:"symbols"},beginner:{keywords:["badge","shield"],char:'🔰',fitzpatrick_scale:false,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:'♻️',fitzpatrick_scale:false,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:'🈯',fitzpatrick_scale:false,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:'💹',fitzpatrick_scale:false,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:'❇️',fitzpatrick_scale:false,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:'✳️',fitzpatrick_scale:false,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:'❎',fitzpatrick_scale:false,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:'✅',fitzpatrick_scale:false,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:'💠',fitzpatrick_scale:false,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:'🌀',fitzpatrick_scale:false,category:"symbols"},loop:{keywords:["tape","cassette"],char:'➿',fitzpatrick_scale:false,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:'🌐',fitzpatrick_scale:false,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:'Ⓜ️',fitzpatrick_scale:false,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:'🏧',fitzpatrick_scale:false,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:'🈂️',fitzpatrick_scale:false,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:'🛂',fitzpatrick_scale:false,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:'🛃',fitzpatrick_scale:false,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:'🛄',fitzpatrick_scale:false,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:'🛅',fitzpatrick_scale:false,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:'♿',fitzpatrick_scale:false,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:'🚭',fitzpatrick_scale:false,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:'🚾',fitzpatrick_scale:false,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:'🅿️',fitzpatrick_scale:false,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:'🚰',fitzpatrick_scale:false,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:'🚹',fitzpatrick_scale:false,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:'🚺',fitzpatrick_scale:false,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:'🚼',fitzpatrick_scale:false,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:'🚻',fitzpatrick_scale:false,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:'🚮',fitzpatrick_scale:false,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:'🎦',fitzpatrick_scale:false,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:'📶',fitzpatrick_scale:false,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:'🈁',fitzpatrick_scale:false,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:'🆖',fitzpatrick_scale:false,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:'🆗',fitzpatrick_scale:false,category:"symbols"},up:{keywords:["blue-square","above","high"],char:'🆙',fitzpatrick_scale:false,category:"symbols"},cool:{keywords:["words","blue-square"],char:'🆒',fitzpatrick_scale:false,category:"symbols"},new:{keywords:["blue-square","words","start"],char:'🆕',fitzpatrick_scale:false,category:"symbols"},free:{keywords:["blue-square","words"],char:'🆓',fitzpatrick_scale:false,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:'0️⃣',fitzpatrick_scale:false,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:'1️⃣',fitzpatrick_scale:false,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:'2️⃣',fitzpatrick_scale:false,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:'3️⃣',fitzpatrick_scale:false,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:'4️⃣',fitzpatrick_scale:false,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:'5️⃣',fitzpatrick_scale:false,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:'6️⃣',fitzpatrick_scale:false,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:'7️⃣',fitzpatrick_scale:false,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:'8️⃣',fitzpatrick_scale:false,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:'9️⃣',fitzpatrick_scale:false,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:'🔟',fitzpatrick_scale:false,category:"symbols"},asterisk:{keywords:["star","keycap"],char:'*⃣',fitzpatrick_scale:false,category:"symbols"},eject_button:{keywords:["blue-square"],char:'⏏️',fitzpatrick_scale:false,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:'▶️',fitzpatrick_scale:false,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:'⏸',fitzpatrick_scale:false,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:'⏭',fitzpatrick_scale:false,category:"symbols"},stop_button:{keywords:["blue-square"],char:'⏹',fitzpatrick_scale:false,category:"symbols"},record_button:{keywords:["blue-square"],char:'⏺',fitzpatrick_scale:false,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:'⏯',fitzpatrick_scale:false,category:"symbols"},previous_track_button:{keywords:["backward"],char:'⏮',fitzpatrick_scale:false,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:'⏩',fitzpatrick_scale:false,category:"symbols"},rewind:{keywords:["play","blue-square"],char:'⏪',fitzpatrick_scale:false,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:'🔀',fitzpatrick_scale:false,category:"symbols"},repeat:{keywords:["loop","record"],char:'🔁',fitzpatrick_scale:false,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:'🔂',fitzpatrick_scale:false,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:'◀️',fitzpatrick_scale:false,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:'🔼',fitzpatrick_scale:false,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:'🔽',fitzpatrick_scale:false,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:'⏫',fitzpatrick_scale:false,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:'⏬',fitzpatrick_scale:false,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:'➡️',fitzpatrick_scale:false,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:'⬅️',fitzpatrick_scale:false,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:'⬆️',fitzpatrick_scale:false,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:'⬇️',fitzpatrick_scale:false,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:'↗️',fitzpatrick_scale:false,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:'↘️',fitzpatrick_scale:false,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:'↙️',fitzpatrick_scale:false,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:'↖️',fitzpatrick_scale:false,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:'↕️',fitzpatrick_scale:false,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:'↔️',fitzpatrick_scale:false,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:'🔄',fitzpatrick_scale:false,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:'↪️',fitzpatrick_scale:false,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:'↩️',fitzpatrick_scale:false,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:'⤴️',fitzpatrick_scale:false,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:'⤵️',fitzpatrick_scale:false,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:'#️⃣',fitzpatrick_scale:false,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:'ℹ️',fitzpatrick_scale:false,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:'🔤',fitzpatrick_scale:false,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:'🔡',fitzpatrick_scale:false,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:'🔠',fitzpatrick_scale:false,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:'🔣',fitzpatrick_scale:false,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:'🎵',fitzpatrick_scale:false,category:"symbols"},notes:{keywords:["music","score"],char:'🎶',fitzpatrick_scale:false,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:'〰️',fitzpatrick_scale:false,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:'➰',fitzpatrick_scale:false,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:'✔️',fitzpatrick_scale:false,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:'🔃',fitzpatrick_scale:false,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:'➕',fitzpatrick_scale:false,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:'➖',fitzpatrick_scale:false,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:'➗',fitzpatrick_scale:false,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:'✖️',fitzpatrick_scale:false,category:"symbols"},infinity:{keywords:["forever"],char:'♾',fitzpatrick_scale:false,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:'💲',fitzpatrick_scale:false,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:'💱',fitzpatrick_scale:false,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:'©️',fitzpatrick_scale:false,category:"symbols"},registered:{keywords:["alphabet","circle"],char:'®️',fitzpatrick_scale:false,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:'™️',fitzpatrick_scale:false,category:"symbols"},end:{keywords:["words","arrow"],char:'🔚',fitzpatrick_scale:false,category:"symbols"},back:{keywords:["arrow","words","return"],char:'🔙',fitzpatrick_scale:false,category:"symbols"},on:{keywords:["arrow","words"],char:'🔛',fitzpatrick_scale:false,category:"symbols"},top:{keywords:["words","blue-square"],char:'🔝',fitzpatrick_scale:false,category:"symbols"},soon:{keywords:["arrow","words"],char:'🔜',fitzpatrick_scale:false,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:'☑️',fitzpatrick_scale:false,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:'🔘',fitzpatrick_scale:false,category:"symbols"},white_circle:{keywords:["shape","round"],char:'⚪',fitzpatrick_scale:false,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:'⚫',fitzpatrick_scale:false,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:'🔴',fitzpatrick_scale:false,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:'🔵',fitzpatrick_scale:false,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:'🔸',fitzpatrick_scale:false,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:'🔹',fitzpatrick_scale:false,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:'🔶',fitzpatrick_scale:false,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:'🔷',fitzpatrick_scale:false,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:'🔺',fitzpatrick_scale:false,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:'▪️',fitzpatrick_scale:false,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:'▫️',fitzpatrick_scale:false,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:'⬛',fitzpatrick_scale:false,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:'⬜',fitzpatrick_scale:false,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:'🔻',fitzpatrick_scale:false,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:'◼️',fitzpatrick_scale:false,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:'◻️',fitzpatrick_scale:false,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:'◾',fitzpatrick_scale:false,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:'◽',fitzpatrick_scale:false,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:'🔲',fitzpatrick_scale:false,category:"symbols"},white_square_button:{keywords:["shape","input"],char:'🔳',fitzpatrick_scale:false,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:'🔈',fitzpatrick_scale:false,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:'🔉',fitzpatrick_scale:false,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:'🔊',fitzpatrick_scale:false,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:'🔇',fitzpatrick_scale:false,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:'📣',fitzpatrick_scale:false,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:'📢',fitzpatrick_scale:false,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:'🔔',fitzpatrick_scale:false,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:'🔕',fitzpatrick_scale:false,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:'🃏',fitzpatrick_scale:false,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:'🀄',fitzpatrick_scale:false,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:'♠️',fitzpatrick_scale:false,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:'♣️',fitzpatrick_scale:false,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:'♥️',fitzpatrick_scale:false,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:'♦️',fitzpatrick_scale:false,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:'🎴',fitzpatrick_scale:false,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:'💭',fitzpatrick_scale:false,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:'🗯',fitzpatrick_scale:false,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:'💬',fitzpatrick_scale:false,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:'🗨',fitzpatrick_scale:false,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:'🕐',fitzpatrick_scale:false,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:'🕑',fitzpatrick_scale:false,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:'🕒',fitzpatrick_scale:false,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:'🕓',fitzpatrick_scale:false,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:'🕔',fitzpatrick_scale:false,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:'🕕',fitzpatrick_scale:false,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:'🕖',fitzpatrick_scale:false,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:'🕗',fitzpatrick_scale:false,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:'🕘',fitzpatrick_scale:false,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:'🕙',fitzpatrick_scale:false,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:'🕚',fitzpatrick_scale:false,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:'🕛',fitzpatrick_scale:false,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:'🕜',fitzpatrick_scale:false,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:'🕝',fitzpatrick_scale:false,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:'🕞',fitzpatrick_scale:false,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:'🕟',fitzpatrick_scale:false,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:'🕠',fitzpatrick_scale:false,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:'🕡',fitzpatrick_scale:false,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:'🕢',fitzpatrick_scale:false,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:'🕣',fitzpatrick_scale:false,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:'🕤',fitzpatrick_scale:false,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:'🕥',fitzpatrick_scale:false,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:'🕦',fitzpatrick_scale:false,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:'🕧',fitzpatrick_scale:false,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:'🇦🇫',fitzpatrick_scale:false,category:"flags"},aland_islands:{keywords:["Åland","islands","flag","nation","country","banner"],char:'🇦🇽',fitzpatrick_scale:false,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:'🇦🇱',fitzpatrick_scale:false,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:'🇩🇿',fitzpatrick_scale:false,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:'🇦🇸',fitzpatrick_scale:false,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:'🇦🇩',fitzpatrick_scale:false,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:'🇦🇴',fitzpatrick_scale:false,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:'🇦🇮',fitzpatrick_scale:false,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:'🇦🇶',fitzpatrick_scale:false,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:'🇦🇬',fitzpatrick_scale:false,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:'🇦🇷',fitzpatrick_scale:false,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:'🇦🇲',fitzpatrick_scale:false,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:'🇦🇼',fitzpatrick_scale:false,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:'🇦🇺',fitzpatrick_scale:false,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:'🇦🇹',fitzpatrick_scale:false,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:'🇦🇿',fitzpatrick_scale:false,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:'🇧🇸',fitzpatrick_scale:false,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:'🇧🇭',fitzpatrick_scale:false,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:'🇧🇩',fitzpatrick_scale:false,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:'🇧🇧',fitzpatrick_scale:false,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:'🇧🇾',fitzpatrick_scale:false,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:'🇧🇪',fitzpatrick_scale:false,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:'🇧🇿',fitzpatrick_scale:false,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:'🇧🇯',fitzpatrick_scale:false,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:'🇧🇲',fitzpatrick_scale:false,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:'🇧🇹',fitzpatrick_scale:false,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:'🇧🇴',fitzpatrick_scale:false,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:'🇧🇶',fitzpatrick_scale:false,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:'🇧🇦',fitzpatrick_scale:false,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:'🇧🇼',fitzpatrick_scale:false,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:'🇧🇷',fitzpatrick_scale:false,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:'🇮🇴',fitzpatrick_scale:false,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:'🇻🇬',fitzpatrick_scale:false,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:'🇧🇳',fitzpatrick_scale:false,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:'🇧🇬',fitzpatrick_scale:false,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:'🇧🇫',fitzpatrick_scale:false,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:'🇧🇮',fitzpatrick_scale:false,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:'🇨🇻',fitzpatrick_scale:false,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:'🇰🇭',fitzpatrick_scale:false,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:'🇨🇲',fitzpatrick_scale:false,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:'🇨🇦',fitzpatrick_scale:false,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:'🇮🇨',fitzpatrick_scale:false,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:'🇰🇾',fitzpatrick_scale:false,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:'🇨🇫',fitzpatrick_scale:false,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:'🇹🇩',fitzpatrick_scale:false,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:'🇨🇱',fitzpatrick_scale:false,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:'🇨🇳',fitzpatrick_scale:false,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:'🇨🇽',fitzpatrick_scale:false,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:'🇨🇨',fitzpatrick_scale:false,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:'🇨🇴',fitzpatrick_scale:false,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:'🇰🇲',fitzpatrick_scale:false,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:'🇨🇬',fitzpatrick_scale:false,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:'🇨🇩',fitzpatrick_scale:false,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:'🇨🇰',fitzpatrick_scale:false,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:'🇨🇷',fitzpatrick_scale:false,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:'🇭🇷',fitzpatrick_scale:false,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:'🇨🇺',fitzpatrick_scale:false,category:"flags"},curacao:{keywords:["curaçao","flag","nation","country","banner"],char:'🇨🇼',fitzpatrick_scale:false,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:'🇨🇾',fitzpatrick_scale:false,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:'🇨🇿',fitzpatrick_scale:false,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:'🇩🇰',fitzpatrick_scale:false,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:'🇩🇯',fitzpatrick_scale:false,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:'🇩🇲',fitzpatrick_scale:false,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:'🇩🇴',fitzpatrick_scale:false,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:'🇪🇨',fitzpatrick_scale:false,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:'🇪🇬',fitzpatrick_scale:false,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:'🇸🇻',fitzpatrick_scale:false,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:'🇬🇶',fitzpatrick_scale:false,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:'🇪🇷',fitzpatrick_scale:false,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:'🇪🇪',fitzpatrick_scale:false,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:'🇪🇹',fitzpatrick_scale:false,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:'🇪🇺',fitzpatrick_scale:false,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:'🇫🇰',fitzpatrick_scale:false,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:'🇫🇴',fitzpatrick_scale:false,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:'🇫🇯',fitzpatrick_scale:false,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:'🇫🇮',fitzpatrick_scale:false,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:'🇫🇷',fitzpatrick_scale:false,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:'🇬🇫',fitzpatrick_scale:false,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:'🇵🇫',fitzpatrick_scale:false,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:'🇹🇫',fitzpatrick_scale:false,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:'🇬🇦',fitzpatrick_scale:false,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:'🇬🇲',fitzpatrick_scale:false,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:'🇬🇪',fitzpatrick_scale:false,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:'🇩🇪',fitzpatrick_scale:false,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:'🇬🇭',fitzpatrick_scale:false,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:'🇬🇮',fitzpatrick_scale:false,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:'🇬🇷',fitzpatrick_scale:false,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:'🇬🇱',fitzpatrick_scale:false,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:'🇬🇩',fitzpatrick_scale:false,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:'🇬🇵',fitzpatrick_scale:false,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:'🇬🇺',fitzpatrick_scale:false,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:'🇬🇹',fitzpatrick_scale:false,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:'🇬🇬',fitzpatrick_scale:false,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:'🇬🇳',fitzpatrick_scale:false,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:'🇬🇼',fitzpatrick_scale:false,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:'🇬🇾',fitzpatrick_scale:false,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:'🇭🇹',fitzpatrick_scale:false,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:'🇭🇳',fitzpatrick_scale:false,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:'🇭🇰',fitzpatrick_scale:false,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:'🇭🇺',fitzpatrick_scale:false,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:'🇮🇸',fitzpatrick_scale:false,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:'🇮🇳',fitzpatrick_scale:false,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:'🇮🇩',fitzpatrick_scale:false,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:'🇮🇷',fitzpatrick_scale:false,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:'🇮🇶',fitzpatrick_scale:false,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:'🇮🇪',fitzpatrick_scale:false,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:'🇮🇲',fitzpatrick_scale:false,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:'🇮🇱',fitzpatrick_scale:false,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:'🇮🇹',fitzpatrick_scale:false,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:'🇨🇮',fitzpatrick_scale:false,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:'🇯🇲',fitzpatrick_scale:false,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:'🇯🇵',fitzpatrick_scale:false,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:'🇯🇪',fitzpatrick_scale:false,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:'🇯🇴',fitzpatrick_scale:false,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:'🇰🇿',fitzpatrick_scale:false,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:'🇰🇪',fitzpatrick_scale:false,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:'🇰🇮',fitzpatrick_scale:false,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:'🇽🇰',fitzpatrick_scale:false,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:'🇰🇼',fitzpatrick_scale:false,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:'🇰🇬',fitzpatrick_scale:false,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:'🇱🇦',fitzpatrick_scale:false,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:'🇱🇻',fitzpatrick_scale:false,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:'🇱🇧',fitzpatrick_scale:false,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:'🇱🇸',fitzpatrick_scale:false,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:'🇱🇷',fitzpatrick_scale:false,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:'🇱🇾',fitzpatrick_scale:false,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:'🇱🇮',fitzpatrick_scale:false,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:'🇱🇹',fitzpatrick_scale:false,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:'🇱🇺',fitzpatrick_scale:false,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:'🇲🇴',fitzpatrick_scale:false,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:'🇲🇰',fitzpatrick_scale:false,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:'🇲🇬',fitzpatrick_scale:false,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:'🇲🇼',fitzpatrick_scale:false,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:'🇲🇾',fitzpatrick_scale:false,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:'🇲🇻',fitzpatrick_scale:false,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:'🇲🇱',fitzpatrick_scale:false,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:'🇲🇹',fitzpatrick_scale:false,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:'🇲🇭',fitzpatrick_scale:false,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:'🇲🇶',fitzpatrick_scale:false,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:'🇲🇷',fitzpatrick_scale:false,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:'🇲🇺',fitzpatrick_scale:false,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:'🇾🇹',fitzpatrick_scale:false,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:'🇲🇽',fitzpatrick_scale:false,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:'🇫🇲',fitzpatrick_scale:false,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:'🇲🇩',fitzpatrick_scale:false,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:'🇲🇨',fitzpatrick_scale:false,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:'🇲🇳',fitzpatrick_scale:false,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:'🇲🇪',fitzpatrick_scale:false,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:'🇲🇸',fitzpatrick_scale:false,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:'🇲🇦',fitzpatrick_scale:false,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:'🇲🇿',fitzpatrick_scale:false,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:'🇲🇲',fitzpatrick_scale:false,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:'🇳🇦',fitzpatrick_scale:false,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:'🇳🇷',fitzpatrick_scale:false,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:'🇳🇵',fitzpatrick_scale:false,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:'🇳🇱',fitzpatrick_scale:false,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:'🇳🇨',fitzpatrick_scale:false,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:'🇳🇿',fitzpatrick_scale:false,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:'🇳🇮',fitzpatrick_scale:false,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:'🇳🇪',fitzpatrick_scale:false,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:'🇳🇬',fitzpatrick_scale:false,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:'🇳🇺',fitzpatrick_scale:false,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:'🇳🇫',fitzpatrick_scale:false,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:'🇲🇵',fitzpatrick_scale:false,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:'🇰🇵',fitzpatrick_scale:false,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:'🇳🇴',fitzpatrick_scale:false,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:'🇴🇲',fitzpatrick_scale:false,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:'🇵🇰',fitzpatrick_scale:false,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:'🇵🇼',fitzpatrick_scale:false,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:'🇵🇸',fitzpatrick_scale:false,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:'🇵🇦',fitzpatrick_scale:false,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:'🇵🇬',fitzpatrick_scale:false,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:'🇵🇾',fitzpatrick_scale:false,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:'🇵🇪',fitzpatrick_scale:false,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:'🇵🇭',fitzpatrick_scale:false,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:'🇵🇳',fitzpatrick_scale:false,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:'🇵🇱',fitzpatrick_scale:false,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:'🇵🇹',fitzpatrick_scale:false,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:'🇵🇷',fitzpatrick_scale:false,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:'🇶🇦',fitzpatrick_scale:false,category:"flags"},reunion:{keywords:["réunion","flag","nation","country","banner"],char:'🇷🇪',fitzpatrick_scale:false,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:'🇷🇴',fitzpatrick_scale:false,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:'🇷🇺',fitzpatrick_scale:false,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:'🇷🇼',fitzpatrick_scale:false,category:"flags"},st_barthelemy:{keywords:["saint","barthélemy","flag","nation","country","banner"],char:'🇧🇱',fitzpatrick_scale:false,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:'🇸🇭',fitzpatrick_scale:false,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:'🇰🇳',fitzpatrick_scale:false,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:'🇱🇨',fitzpatrick_scale:false,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:'🇵🇲',fitzpatrick_scale:false,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:'🇻🇨',fitzpatrick_scale:false,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:'🇼🇸',fitzpatrick_scale:false,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:'🇸🇲',fitzpatrick_scale:false,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:'🇸🇹',fitzpatrick_scale:false,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:'🇸🇦',fitzpatrick_scale:false,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:'🇸🇳',fitzpatrick_scale:false,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:'🇷🇸',fitzpatrick_scale:false,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:'🇸🇨',fitzpatrick_scale:false,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:'🇸🇱',fitzpatrick_scale:false,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:'🇸🇬',fitzpatrick_scale:false,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:'🇸🇽',fitzpatrick_scale:false,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:'🇸🇰',fitzpatrick_scale:false,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:'🇸🇮',fitzpatrick_scale:false,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:'🇸🇧',fitzpatrick_scale:false,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:'🇸🇴',fitzpatrick_scale:false,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:'🇿🇦',fitzpatrick_scale:false,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:'🇬🇸',fitzpatrick_scale:false,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:'🇰🇷',fitzpatrick_scale:false,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:'🇸🇸',fitzpatrick_scale:false,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:'🇪🇸',fitzpatrick_scale:false,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:'🇱🇰',fitzpatrick_scale:false,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:'🇸🇩',fitzpatrick_scale:false,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:'🇸🇷',fitzpatrick_scale:false,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:'🇸🇿',fitzpatrick_scale:false,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:'🇸🇪',fitzpatrick_scale:false,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:'🇨🇭',fitzpatrick_scale:false,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:'🇸🇾',fitzpatrick_scale:false,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:'🇹🇼',fitzpatrick_scale:false,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:'🇹🇯',fitzpatrick_scale:false,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:'🇹🇿',fitzpatrick_scale:false,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:'🇹🇭',fitzpatrick_scale:false,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:'🇹🇱',fitzpatrick_scale:false,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:'🇹🇬',fitzpatrick_scale:false,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:'🇹🇰',fitzpatrick_scale:false,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:'🇹🇴',fitzpatrick_scale:false,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:'🇹🇹',fitzpatrick_scale:false,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:'🇹🇳',fitzpatrick_scale:false,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:'🇹🇷',fitzpatrick_scale:false,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:'🇹🇲',fitzpatrick_scale:false,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:'🇹🇨',fitzpatrick_scale:false,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:'🇹🇻',fitzpatrick_scale:false,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:'🇺🇬',fitzpatrick_scale:false,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:'🇺🇦',fitzpatrick_scale:false,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:'🇦🇪',fitzpatrick_scale:false,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:'🇬🇧',fitzpatrick_scale:false,category:"flags"},england:{keywords:["flag","english"],char:'🏴󠁧󠁢󠁥󠁮󠁧󠁿',fitzpatrick_scale:false,category:"flags"},scotland:{keywords:["flag","scottish"],char:'🏴󠁧󠁢󠁳󠁣󠁴󠁿',fitzpatrick_scale:false,category:"flags"},wales:{keywords:["flag","welsh"],char:'🏴󠁧󠁢󠁷󠁬󠁳󠁿',fitzpatrick_scale:false,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:'🇺🇸',fitzpatrick_scale:false,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:'🇻🇮',fitzpatrick_scale:false,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:'🇺🇾',fitzpatrick_scale:false,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:'🇺🇿',fitzpatrick_scale:false,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:'🇻🇺',fitzpatrick_scale:false,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:'🇻🇦',fitzpatrick_scale:false,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:'🇻🇪',fitzpatrick_scale:false,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:'🇻🇳',fitzpatrick_scale:false,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:'🇼🇫',fitzpatrick_scale:false,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:'🇪🇭',fitzpatrick_scale:false,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:'🇾🇪',fitzpatrick_scale:false,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:'🇿🇲',fitzpatrick_scale:false,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:'🇿🇼',fitzpatrick_scale:false,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:'🇺🇳',fitzpatrick_scale:false,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:'🏴‍☠️',fitzpatrick_scale:false,category:"flags"}}); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.min.js b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.min.js new file mode 100644 index 0000000..37f3bcf --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.min.js @@ -0,0 +1,3 @@ +// Source: npm package: emojilib +// Images provided by twemoji: https://github.com/twitter/twemoji +window.tinymce.Resource.add("tinymce.plugins.emoticons",{100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:'\u{1f4af}',fitzpatrick_scale:!1,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:'\u{1f522}',fitzpatrick_scale:!1,category:"symbols"},grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:'\u{1f600}',fitzpatrick_scale:!1,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:'\u{1f62c}',fitzpatrick_scale:!1,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:'\u{1f601}',fitzpatrick_scale:!1,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:'\u{1f602}',fitzpatrick_scale:!1,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:'\u{1f923}',fitzpatrick_scale:!1,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:'\u{1f973}',fitzpatrick_scale:!1,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:'\u{1f603}',fitzpatrick_scale:!1,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:'\u{1f604}',fitzpatrick_scale:!1,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:'\u{1f605}',fitzpatrick_scale:!1,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:'\u{1f606}',fitzpatrick_scale:!1,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:'\u{1f607}',fitzpatrick_scale:!1,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:'\u{1f609}',fitzpatrick_scale:!1,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:'\u{1f60a}',fitzpatrick_scale:!1,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:'\u{1f642}',fitzpatrick_scale:!1,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:'\u{1f643}',fitzpatrick_scale:!1,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:'\u263a\ufe0f',fitzpatrick_scale:!1,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:'\u{1f60b}',fitzpatrick_scale:!1,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:'\u{1f60c}',fitzpatrick_scale:!1,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:'\u{1f60d}',fitzpatrick_scale:!1,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:'\u{1f970}',fitzpatrick_scale:!1,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'\u{1f618}',fitzpatrick_scale:!1,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:'\u{1f617}',fitzpatrick_scale:!1,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:'\u{1f619}',fitzpatrick_scale:!1,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'\u{1f61a}',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:'\u{1f61c}',fitzpatrick_scale:!1,category:"people"},zany:{keywords:["face","goofy","crazy"],char:'\u{1f92a}',fitzpatrick_scale:!1,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:'\u{1f928}',fitzpatrick_scale:!1,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:'\u{1f9d0}',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:'\u{1f61d}',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:'\u{1f61b}',fitzpatrick_scale:!1,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:'\u{1f911}',fitzpatrick_scale:!1,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:'\u{1f913}',fitzpatrick_scale:!1,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:'\u{1f60e}',fitzpatrick_scale:!1,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:'\u{1f929}',fitzpatrick_scale:!1,category:"people"},clown_face:{keywords:["face"],char:'\u{1f921}',fitzpatrick_scale:!1,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:'\u{1f920}',fitzpatrick_scale:!1,category:"people"},hugs:{keywords:["face","smile","hug"],char:'\u{1f917}',fitzpatrick_scale:!1,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:'\u{1f60f}',fitzpatrick_scale:!1,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:'\u{1f636}',fitzpatrick_scale:!1,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:'\u{1f610}',fitzpatrick_scale:!1,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:'\u{1f611}',fitzpatrick_scale:!1,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:'\u{1f612}',fitzpatrick_scale:!1,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:'\u{1f644}',fitzpatrick_scale:!1,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:'\u{1f914}',fitzpatrick_scale:!1,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:'\u{1f925}',fitzpatrick_scale:!1,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:'\u{1f92d}',fitzpatrick_scale:!1,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:'\u{1f92b}',fitzpatrick_scale:!1,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:'\u{1f92c}',fitzpatrick_scale:!1,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:'\u{1f92f}',fitzpatrick_scale:!1,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:'\u{1f633}',fitzpatrick_scale:!1,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:'\u{1f61e}',fitzpatrick_scale:!1,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:'\u{1f61f}',fitzpatrick_scale:!1,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:'\u{1f620}',fitzpatrick_scale:!1,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:'\u{1f621}',fitzpatrick_scale:!1,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:'\u{1f614}',fitzpatrick_scale:!1,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:'\u{1f615}',fitzpatrick_scale:!1,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:'\u{1f641}',fitzpatrick_scale:!1,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:'\u2639',fitzpatrick_scale:!1,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:'\u{1f623}',fitzpatrick_scale:!1,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:'\u{1f616}',fitzpatrick_scale:!1,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:'\u{1f62b}',fitzpatrick_scale:!1,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:'\u{1f629}',fitzpatrick_scale:!1,category:"people"},pleading:{keywords:["face","begging","mercy"],char:'\u{1f97a}',fitzpatrick_scale:!1,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:'\u{1f624}',fitzpatrick_scale:!1,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:'\u{1f62e}',fitzpatrick_scale:!1,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:'\u{1f631}',fitzpatrick_scale:!1,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:'\u{1f628}',fitzpatrick_scale:!1,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:'\u{1f630}',fitzpatrick_scale:!1,category:"people"},hushed:{keywords:["face","woo","shh"],char:'\u{1f62f}',fitzpatrick_scale:!1,category:"people"},frowning:{keywords:["face","aw","what"],char:'\u{1f626}',fitzpatrick_scale:!1,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:'\u{1f627}',fitzpatrick_scale:!1,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:'\u{1f622}',fitzpatrick_scale:!1,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:'\u{1f625}',fitzpatrick_scale:!1,category:"people"},drooling_face:{keywords:["face"],char:'\u{1f924}',fitzpatrick_scale:!1,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:'\u{1f62a}',fitzpatrick_scale:!1,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:'\u{1f613}',fitzpatrick_scale:!1,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:'\u{1f975}',fitzpatrick_scale:!1,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:'\u{1f976}',fitzpatrick_scale:!1,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:'\u{1f62d}',fitzpatrick_scale:!1,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:'\u{1f635}',fitzpatrick_scale:!1,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:'\u{1f632}',fitzpatrick_scale:!1,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:'\u{1f910}',fitzpatrick_scale:!1,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:'\u{1f922}',fitzpatrick_scale:!1,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:'\u{1f927}',fitzpatrick_scale:!1,category:"people"},vomiting:{keywords:["face","sick"],char:'\u{1f92e}',fitzpatrick_scale:!1,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:'\u{1f637}',fitzpatrick_scale:!1,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:'\u{1f912}',fitzpatrick_scale:!1,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:'\u{1f915}',fitzpatrick_scale:!1,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:'\u{1f974}',fitzpatrick_scale:!1,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:'\u{1f634}',fitzpatrick_scale:!1,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:'\u{1f4a4}',fitzpatrick_scale:!1,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:'\u{1f4a9}',fitzpatrick_scale:!1,category:"people"},smiling_imp:{keywords:["devil","horns"],char:'\u{1f608}',fitzpatrick_scale:!1,category:"people"},imp:{keywords:["devil","angry","horns"],char:'\u{1f47f}',fitzpatrick_scale:!1,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:'\u{1f479}',fitzpatrick_scale:!1,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:'\u{1f47a}',fitzpatrick_scale:!1,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:'\u{1f480}',fitzpatrick_scale:!1,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:'\u{1f47b}',fitzpatrick_scale:!1,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:'\u{1f47d}',fitzpatrick_scale:!1,category:"people"},robot:{keywords:["computer","machine","bot"],char:'\u{1f916}',fitzpatrick_scale:!1,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:'\u{1f63a}',fitzpatrick_scale:!1,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:'\u{1f638}',fitzpatrick_scale:!1,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:'\u{1f639}',fitzpatrick_scale:!1,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:'\u{1f63b}',fitzpatrick_scale:!1,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:'\u{1f63c}',fitzpatrick_scale:!1,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:'\u{1f63d}',fitzpatrick_scale:!1,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:'\u{1f640}',fitzpatrick_scale:!1,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:'\u{1f63f}',fitzpatrick_scale:!1,category:"people"},pouting_cat:{keywords:["animal","cats"],char:'\u{1f63e}',fitzpatrick_scale:!1,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:'\u{1f932}',fitzpatrick_scale:!0,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:'\u{1f64c}',fitzpatrick_scale:!0,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:'\u{1f44f}',fitzpatrick_scale:!0,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:'\u{1f44b}',fitzpatrick_scale:!0,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:'\u{1f919}',fitzpatrick_scale:!0,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:'\u{1f44d}',fitzpatrick_scale:!0,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:'\u{1f44e}',fitzpatrick_scale:!0,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:'\u{1f44a}',fitzpatrick_scale:!0,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:'\u270a',fitzpatrick_scale:!0,category:"people"},fist_left:{keywords:["hand","fistbump"],char:'\u{1f91b}',fitzpatrick_scale:!0,category:"people"},fist_right:{keywords:["hand","fistbump"],char:'\u{1f91c}',fitzpatrick_scale:!0,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:'\u270c',fitzpatrick_scale:!0,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:'\u{1f44c}',fitzpatrick_scale:!0,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:'\u270b',fitzpatrick_scale:!0,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:'\u{1f91a}',fitzpatrick_scale:!0,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:'\u{1f450}',fitzpatrick_scale:!0,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:'\u{1f4aa}',fitzpatrick_scale:!0,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:'\u{1f64f}',fitzpatrick_scale:!0,category:"people"},foot:{keywords:["kick","stomp"],char:'\u{1f9b6}',fitzpatrick_scale:!0,category:"people"},leg:{keywords:["kick","limb"],char:'\u{1f9b5}',fitzpatrick_scale:!0,category:"people"},handshake:{keywords:["agreement","shake"],char:'\u{1f91d}',fitzpatrick_scale:!1,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:'\u261d',fitzpatrick_scale:!0,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:'\u{1f446}',fitzpatrick_scale:!0,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:'\u{1f447}',fitzpatrick_scale:!0,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:'\u{1f448}',fitzpatrick_scale:!0,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:'\u{1f449}',fitzpatrick_scale:!0,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:'\u{1f595}',fitzpatrick_scale:!0,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:'\u{1f590}',fitzpatrick_scale:!0,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:'\u{1f91f}',fitzpatrick_scale:!0,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:'\u{1f918}',fitzpatrick_scale:!0,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:'\u{1f91e}',fitzpatrick_scale:!0,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:'\u{1f596}',fitzpatrick_scale:!0,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:'\u270d',fitzpatrick_scale:!0,category:"people"},selfie:{keywords:["camera","phone"],char:'\u{1f933}',fitzpatrick_scale:!0,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:'\u{1f485}',fitzpatrick_scale:!0,category:"people"},lips:{keywords:["mouth","kiss"],char:'\u{1f444}',fitzpatrick_scale:!1,category:"people"},tooth:{keywords:["teeth","dentist"],char:'\u{1f9b7}',fitzpatrick_scale:!1,category:"people"},tongue:{keywords:["mouth","playful"],char:'\u{1f445}',fitzpatrick_scale:!1,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:'\u{1f442}',fitzpatrick_scale:!0,category:"people"},nose:{keywords:["smell","sniff"],char:'\u{1f443}',fitzpatrick_scale:!0,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:'\u{1f441}',fitzpatrick_scale:!1,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:'\u{1f440}',fitzpatrick_scale:!1,category:"people"},brain:{keywords:["smart","intelligent"],char:'\u{1f9e0}',fitzpatrick_scale:!1,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:'\u{1f464}',fitzpatrick_scale:!1,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:'\u{1f465}',fitzpatrick_scale:!1,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:'\u{1f5e3}',fitzpatrick_scale:!1,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:'\u{1f476}',fitzpatrick_scale:!0,category:"people"},child:{keywords:["gender-neutral","young"],char:'\u{1f9d2}',fitzpatrick_scale:!0,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:'\u{1f466}',fitzpatrick_scale:!0,category:"people"},girl:{keywords:["female","woman","teenager"],char:'\u{1f467}',fitzpatrick_scale:!0,category:"people"},adult:{keywords:["gender-neutral","person"],char:'\u{1f9d1}',fitzpatrick_scale:!0,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:'\u{1f468}',fitzpatrick_scale:!0,category:"people"},woman:{keywords:["female","girls","lady"],char:'\u{1f469}',fitzpatrick_scale:!0,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:'\u{1f471}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:'\u{1f471}',fitzpatrick_scale:!0,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:'\u{1f9d4}',fitzpatrick_scale:!0,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:'\u{1f9d3}',fitzpatrick_scale:!0,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:'\u{1f474}',fitzpatrick_scale:!0,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:'\u{1f475}',fitzpatrick_scale:!0,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:'\u{1f472}',fitzpatrick_scale:!0,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:'\u{1f9d5}',fitzpatrick_scale:!0,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:'\u{1f473}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:'\u{1f473}',fitzpatrick_scale:!0,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:'\u{1f46e}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:'\u{1f46e}',fitzpatrick_scale:!0,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:'\u{1f477}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:'\u{1f477}',fitzpatrick_scale:!0,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:'\u{1f482}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:'\u{1f482}',fitzpatrick_scale:!0,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:'\u{1f575}\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},male_detective:{keywords:["human","spy","detective"],char:'\u{1f575}',fitzpatrick_scale:!0,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:'\u{1f469}\u200d\u2695\ufe0f',fitzpatrick_scale:!0,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:'\u{1f468}\u200d\u2695\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:'\u{1f469}\u200d\u{1f33e}',fitzpatrick_scale:!0,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:'\u{1f468}\u200d\u{1f33e}',fitzpatrick_scale:!0,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:'\u{1f469}\u200d\u{1f373}',fitzpatrick_scale:!0,category:"people"},man_cook:{keywords:["chef","man","human"],char:'\u{1f468}\u200d\u{1f373}',fitzpatrick_scale:!0,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:'\u{1f469}\u200d\u{1f393}',fitzpatrick_scale:!0,category:"people"},man_student:{keywords:["graduate","man","human"],char:'\u{1f468}\u200d\u{1f393}',fitzpatrick_scale:!0,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:'\u{1f469}\u200d\u{1f3a4}',fitzpatrick_scale:!0,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:'\u{1f468}\u200d\u{1f3a4}',fitzpatrick_scale:!0,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:'\u{1f469}\u200d\u{1f3eb}',fitzpatrick_scale:!0,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:'\u{1f468}\u200d\u{1f3eb}',fitzpatrick_scale:!0,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:'\u{1f469}\u200d\u{1f3ed}',fitzpatrick_scale:!0,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:'\u{1f468}\u200d\u{1f3ed}',fitzpatrick_scale:!0,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:'\u{1f469}\u200d\u{1f4bb}',fitzpatrick_scale:!0,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:'\u{1f468}\u200d\u{1f4bb}',fitzpatrick_scale:!0,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:'\u{1f469}\u200d\u{1f4bc}',fitzpatrick_scale:!0,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:'\u{1f468}\u200d\u{1f4bc}',fitzpatrick_scale:!0,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:'\u{1f469}\u200d\u{1f527}',fitzpatrick_scale:!0,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:'\u{1f468}\u200d\u{1f527}',fitzpatrick_scale:!0,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:'\u{1f469}\u200d\u{1f52c}',fitzpatrick_scale:!0,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:'\u{1f468}\u200d\u{1f52c}',fitzpatrick_scale:!0,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:'\u{1f469}\u200d\u{1f3a8}',fitzpatrick_scale:!0,category:"people"},man_artist:{keywords:["painter","man","human"],char:'\u{1f468}\u200d\u{1f3a8}',fitzpatrick_scale:!0,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:'\u{1f469}\u200d\u{1f692}',fitzpatrick_scale:!0,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:'\u{1f468}\u200d\u{1f692}',fitzpatrick_scale:!0,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:'\u{1f469}\u200d\u2708\ufe0f',fitzpatrick_scale:!0,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:'\u{1f468}\u200d\u2708\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:'\u{1f469}\u200d\u{1f680}',fitzpatrick_scale:!0,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:'\u{1f468}\u200d\u{1f680}',fitzpatrick_scale:!0,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:'\u{1f469}\u200d\u2696\ufe0f',fitzpatrick_scale:!0,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:'\u{1f468}\u200d\u2696\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:'\u{1f9b8}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:'\u{1f9b8}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:'\u{1f9b9}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:'\u{1f9b9}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:'\u{1f936}',fitzpatrick_scale:!0,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:'\u{1f385}',fitzpatrick_scale:!0,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:'\u{1f9d9}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:'\u{1f9d9}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_elf:{keywords:["woman","female"],char:'\u{1f9dd}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_elf:{keywords:["man","male"],char:'\u{1f9dd}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_vampire:{keywords:["woman","female"],char:'\u{1f9db}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:'\u{1f9db}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:'\u{1f9df}\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:'\u{1f9df}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"people"},woman_genie:{keywords:["woman","female"],char:'\u{1f9de}\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"people"},man_genie:{keywords:["man","male"],char:'\u{1f9de}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:'\u{1f9dc}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},merman:{keywords:["man","male","triton"],char:'\u{1f9dc}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_fairy:{keywords:["woman","female"],char:'\u{1f9da}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_fairy:{keywords:["man","male"],char:'\u{1f9da}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},angel:{keywords:["heaven","wings","halo"],char:'\u{1f47c}',fitzpatrick_scale:!0,category:"people"},pregnant_woman:{keywords:["baby"],char:'\u{1f930}',fitzpatrick_scale:!0,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:'\u{1f931}',fitzpatrick_scale:!0,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:'\u{1f478}',fitzpatrick_scale:!0,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:'\u{1f934}',fitzpatrick_scale:!0,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:'\u{1f470}',fitzpatrick_scale:!0,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:'\u{1f935}',fitzpatrick_scale:!0,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:'\u{1f3c3}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:'\u{1f3c3}',fitzpatrick_scale:!0,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:'\u{1f6b6}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},walking_man:{keywords:["human","feet","steps"],char:'\u{1f6b6}',fitzpatrick_scale:!0,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:'\u{1f483}',fitzpatrick_scale:!0,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:'\u{1f57a}',fitzpatrick_scale:!0,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:'\u{1f46f}',fitzpatrick_scale:!1,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:'\u{1f46f}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:'\u{1f46b}',fitzpatrick_scale:!1,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:'\u{1f46c}',fitzpatrick_scale:!1,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:'\u{1f46d}',fitzpatrick_scale:!1,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:'\u{1f647}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},bowing_man:{keywords:["man","male","boy"],char:'\u{1f647}',fitzpatrick_scale:!0,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:'\u{1f926}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:'\u{1f926}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:'\u{1f937}',fitzpatrick_scale:!0,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:'\u{1f937}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:'\u{1f481}',fitzpatrick_scale:!0,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:'\u{1f481}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:'\u{1f645}',fitzpatrick_scale:!0,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:'\u{1f645}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:'\u{1f646}',fitzpatrick_scale:!0,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:'\u{1f646}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:'\u{1f64b}',fitzpatrick_scale:!0,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:'\u{1f64b}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:'\u{1f64e}',fitzpatrick_scale:!0,category:"people"},pouting_man:{keywords:["male","boy","man"],char:'\u{1f64e}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:'\u{1f64d}',fitzpatrick_scale:!0,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:'\u{1f64d}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:'\u{1f487}',fitzpatrick_scale:!0,category:"people"},haircut_man:{keywords:["male","boy","man"],char:'\u{1f487}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:'\u{1f486}',fitzpatrick_scale:!0,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:'\u{1f486}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:'\u{1f9d6}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:'\u{1f9d6}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'\u{1f491}',fitzpatrick_scale:!1,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f469}',fitzpatrick_scale:!1,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f468}',fitzpatrick_scale:!1,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'\u{1f48f}',fitzpatrick_scale:!1,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f469}',fitzpatrick_scale:!1,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:'\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f468}',fitzpatrick_scale:!1,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:'\u{1f46a}',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:'\u{1f469}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:'\u{1f469}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f469}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f469}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:'\u{1f469}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:'\u{1f468}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:'\u{1f468}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f468}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f468}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:'\u{1f468}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:'\u{1f9f6}',fitzpatrick_scale:!1,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:'\u{1f9f5}',fitzpatrick_scale:!1,category:"people"},coat:{keywords:["jacket"],char:'\u{1f9e5}',fitzpatrick_scale:!1,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:'\u{1f97c}',fitzpatrick_scale:!1,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:'\u{1f45a}',fitzpatrick_scale:!1,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:'\u{1f455}',fitzpatrick_scale:!1,category:"people"},jeans:{keywords:["fashion","shopping"],char:'\u{1f456}',fitzpatrick_scale:!1,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:'\u{1f454}',fitzpatrick_scale:!1,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:'\u{1f457}',fitzpatrick_scale:!1,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:'\u{1f459}',fitzpatrick_scale:!1,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:'\u{1f458}',fitzpatrick_scale:!1,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:'\u{1f484}',fitzpatrick_scale:!1,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:'\u{1f48b}',fitzpatrick_scale:!1,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:'\u{1f463}',fitzpatrick_scale:!1,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:'\u{1f97f}',fitzpatrick_scale:!1,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:'\u{1f460}',fitzpatrick_scale:!1,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:'\u{1f461}',fitzpatrick_scale:!1,category:"people"},boot:{keywords:["shoes","fashion"],char:'\u{1f462}',fitzpatrick_scale:!1,category:"people"},mans_shoe:{keywords:["fashion","male"],char:'\u{1f45e}',fitzpatrick_scale:!1,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:'\u{1f45f}',fitzpatrick_scale:!1,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:'\u{1f97e}',fitzpatrick_scale:!1,category:"people"},socks:{keywords:["stockings","clothes"],char:'\u{1f9e6}',fitzpatrick_scale:!1,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:'\u{1f9e4}',fitzpatrick_scale:!1,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:'\u{1f9e3}',fitzpatrick_scale:!1,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:'\u{1f452}',fitzpatrick_scale:!1,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:'\u{1f3a9}',fitzpatrick_scale:!1,category:"people"},billed_hat:{keywords:["cap","baseball"],char:'\u{1f9e2}',fitzpatrick_scale:!1,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:'\u26d1',fitzpatrick_scale:!1,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:'\u{1f393}',fitzpatrick_scale:!1,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:'\u{1f451}',fitzpatrick_scale:!1,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:'\u{1f392}',fitzpatrick_scale:!1,category:"people"},luggage:{keywords:["packing","travel"],char:'\u{1f9f3}',fitzpatrick_scale:!1,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:'\u{1f45d}',fitzpatrick_scale:!1,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:'\u{1f45b}',fitzpatrick_scale:!1,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:'\u{1f45c}',fitzpatrick_scale:!1,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:'\u{1f4bc}',fitzpatrick_scale:!1,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:'\u{1f453}',fitzpatrick_scale:!1,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:'\u{1f576}',fitzpatrick_scale:!1,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:'\u{1f97d}',fitzpatrick_scale:!1,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:'\u{1f48d}',fitzpatrick_scale:!1,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:'\u{1f302}',fitzpatrick_scale:!1,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:'\u{1f436}',fitzpatrick_scale:!1,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:'\u{1f431}',fitzpatrick_scale:!1,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:'\u{1f42d}',fitzpatrick_scale:!1,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:'\u{1f439}',fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:'\u{1f430}',fitzpatrick_scale:!1,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:'\u{1f98a}',fitzpatrick_scale:!1,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:'\u{1f43b}',fitzpatrick_scale:!1,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:'\u{1f43c}',fitzpatrick_scale:!1,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:'\u{1f428}',fitzpatrick_scale:!1,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:'\u{1f42f}',fitzpatrick_scale:!1,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:'\u{1f981}',fitzpatrick_scale:!1,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:'\u{1f42e}',fitzpatrick_scale:!1,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:'\u{1f437}',fitzpatrick_scale:!1,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:'\u{1f43d}',fitzpatrick_scale:!1,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:'\u{1f438}',fitzpatrick_scale:!1,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:'\u{1f991}',fitzpatrick_scale:!1,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:'\u{1f419}',fitzpatrick_scale:!1,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:'\u{1f990}',fitzpatrick_scale:!1,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:'\u{1f435}',fitzpatrick_scale:!1,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:'\u{1f98d}',fitzpatrick_scale:!1,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:'\u{1f648}',fitzpatrick_scale:!1,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:'\u{1f649}',fitzpatrick_scale:!1,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:'\u{1f64a}',fitzpatrick_scale:!1,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:'\u{1f412}',fitzpatrick_scale:!1,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:'\u{1f414}',fitzpatrick_scale:!1,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:'\u{1f427}',fitzpatrick_scale:!1,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:'\u{1f426}',fitzpatrick_scale:!1,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:'\u{1f424}',fitzpatrick_scale:!1,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:'\u{1f423}',fitzpatrick_scale:!1,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:'\u{1f425}',fitzpatrick_scale:!1,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:'\u{1f986}',fitzpatrick_scale:!1,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:'\u{1f985}',fitzpatrick_scale:!1,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:'\u{1f989}',fitzpatrick_scale:!1,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:'\u{1f987}',fitzpatrick_scale:!1,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:'\u{1f43a}',fitzpatrick_scale:!1,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:'\u{1f417}',fitzpatrick_scale:!1,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:'\u{1f434}',fitzpatrick_scale:!1,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:'\u{1f984}',fitzpatrick_scale:!1,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:'\u{1f41d}',fitzpatrick_scale:!1,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:'\u{1f41b}',fitzpatrick_scale:!1,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:'\u{1f98b}',fitzpatrick_scale:!1,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:'\u{1f40c}',fitzpatrick_scale:!1,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:'\u{1f41e}',fitzpatrick_scale:!1,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:'\u{1f41c}',fitzpatrick_scale:!1,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:'\u{1f997}',fitzpatrick_scale:!1,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:'\u{1f577}',fitzpatrick_scale:!1,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:'\u{1f982}',fitzpatrick_scale:!1,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:'\u{1f980}',fitzpatrick_scale:!1,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:'\u{1f40d}',fitzpatrick_scale:!1,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:'\u{1f98e}',fitzpatrick_scale:!1,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:'\u{1f996}',fitzpatrick_scale:!1,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:'\u{1f995}',fitzpatrick_scale:!1,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:'\u{1f422}',fitzpatrick_scale:!1,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:'\u{1f420}',fitzpatrick_scale:!1,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:'\u{1f41f}',fitzpatrick_scale:!1,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:'\u{1f421}',fitzpatrick_scale:!1,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:'\u{1f42c}',fitzpatrick_scale:!1,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:'\u{1f988}',fitzpatrick_scale:!1,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:'\u{1f433}',fitzpatrick_scale:!1,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:'\u{1f40b}',fitzpatrick_scale:!1,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:'\u{1f40a}',fitzpatrick_scale:!1,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:'\u{1f406}',fitzpatrick_scale:!1,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:'\u{1f993}',fitzpatrick_scale:!1,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:'\u{1f405}',fitzpatrick_scale:!1,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:'\u{1f403}',fitzpatrick_scale:!1,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:'\u{1f402}',fitzpatrick_scale:!1,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:'\u{1f404}',fitzpatrick_scale:!1,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:'\u{1f98c}',fitzpatrick_scale:!1,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:'\u{1f42a}',fitzpatrick_scale:!1,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:'\u{1f42b}',fitzpatrick_scale:!1,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:'\u{1f992}',fitzpatrick_scale:!1,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:'\u{1f418}',fitzpatrick_scale:!1,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:'\u{1f98f}',fitzpatrick_scale:!1,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:'\u{1f410}',fitzpatrick_scale:!1,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:'\u{1f40f}',fitzpatrick_scale:!1,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:'\u{1f411}',fitzpatrick_scale:!1,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:'\u{1f40e}',fitzpatrick_scale:!1,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:'\u{1f416}',fitzpatrick_scale:!1,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:'\u{1f400}',fitzpatrick_scale:!1,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:'\u{1f401}',fitzpatrick_scale:!1,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:'\u{1f413}',fitzpatrick_scale:!1,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:'\u{1f983}',fitzpatrick_scale:!1,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:'\u{1f54a}',fitzpatrick_scale:!1,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:'\u{1f415}',fitzpatrick_scale:!1,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:'\u{1f429}',fitzpatrick_scale:!1,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:'\u{1f408}',fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:'\u{1f407}',fitzpatrick_scale:!1,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:'\u{1f43f}',fitzpatrick_scale:!1,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:'\u{1f994}',fitzpatrick_scale:!1,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:'\u{1f99d}',fitzpatrick_scale:!1,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:'\u{1f999}',fitzpatrick_scale:!1,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:'\u{1f99b}',fitzpatrick_scale:!1,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:'\u{1f998}',fitzpatrick_scale:!1,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:'\u{1f9a1}',fitzpatrick_scale:!1,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:'\u{1f9a2}',fitzpatrick_scale:!1,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:'\u{1f99a}',fitzpatrick_scale:!1,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:'\u{1f99c}',fitzpatrick_scale:!1,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:'\u{1f99e}',fitzpatrick_scale:!1,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:'\u{1f99f}',fitzpatrick_scale:!1,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:'\u{1f43e}',fitzpatrick_scale:!1,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:'\u{1f409}',fitzpatrick_scale:!1,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:'\u{1f432}',fitzpatrick_scale:!1,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:'\u{1f335}',fitzpatrick_scale:!1,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:'\u{1f384}',fitzpatrick_scale:!1,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:'\u{1f332}',fitzpatrick_scale:!1,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:'\u{1f333}',fitzpatrick_scale:!1,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:'\u{1f334}',fitzpatrick_scale:!1,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:'\u{1f331}',fitzpatrick_scale:!1,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:'\u{1f33f}',fitzpatrick_scale:!1,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:'\u2618',fitzpatrick_scale:!1,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:'\u{1f340}',fitzpatrick_scale:!1,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:'\u{1f38d}',fitzpatrick_scale:!1,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:'\u{1f38b}',fitzpatrick_scale:!1,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:'\u{1f343}',fitzpatrick_scale:!1,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:'\u{1f342}',fitzpatrick_scale:!1,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:'\u{1f341}',fitzpatrick_scale:!1,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:'\u{1f33e}',fitzpatrick_scale:!1,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:'\u{1f33a}',fitzpatrick_scale:!1,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:'\u{1f33b}',fitzpatrick_scale:!1,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:'\u{1f339}',fitzpatrick_scale:!1,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:'\u{1f940}',fitzpatrick_scale:!1,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:'\u{1f337}',fitzpatrick_scale:!1,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:'\u{1f33c}',fitzpatrick_scale:!1,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:'\u{1f338}',fitzpatrick_scale:!1,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:'\u{1f490}',fitzpatrick_scale:!1,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:'\u{1f344}',fitzpatrick_scale:!1,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:'\u{1f330}',fitzpatrick_scale:!1,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:'\u{1f383}',fitzpatrick_scale:!1,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:'\u{1f41a}',fitzpatrick_scale:!1,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:'\u{1f578}',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:'\u{1f30e}',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:'\u{1f30d}',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:'\u{1f30f}',fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:'\u{1f315}',fitzpatrick_scale:!1,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:'\u{1f316}',fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f317}',fitzpatrick_scale:!1,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f318}',fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f311}',fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f312}',fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f313}',fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:'\u{1f314}',fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31a}',fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31d}',fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31b}',fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31c}',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:'\u{1f31e}',fitzpatrick_scale:!1,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:'\u{1f319}',fitzpatrick_scale:!1,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:'\u2b50',fitzpatrick_scale:!1,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:'\u{1f31f}',fitzpatrick_scale:!1,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:'\u{1f4ab}',fitzpatrick_scale:!1,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:'\u2728',fitzpatrick_scale:!1,category:"animals_and_nature"},comet:{keywords:["space"],char:'\u2604',fitzpatrick_scale:!1,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:'\u2600\ufe0f',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:'\u{1f324}',fitzpatrick_scale:!1,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:'\u26c5',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:'\u{1f325}',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:'\u{1f326}',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:'\u2601\ufe0f',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:'\u{1f327}',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:'\u26c8',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:'\u{1f329}',fitzpatrick_scale:!1,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:'\u26a1',fitzpatrick_scale:!1,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:'\u{1f525}',fitzpatrick_scale:!1,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:'\u{1f4a5}',fitzpatrick_scale:!1,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:'\u2744\ufe0f',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:'\u{1f328}',fitzpatrick_scale:!1,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:'\u26c4',fitzpatrick_scale:!1,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:'\u2603',fitzpatrick_scale:!1,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:'\u{1f32c}',fitzpatrick_scale:!1,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:'\u{1f4a8}',fitzpatrick_scale:!1,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:'\u{1f32a}',fitzpatrick_scale:!1,category:"animals_and_nature"},fog:{keywords:["weather"],char:'\u{1f32b}',fitzpatrick_scale:!1,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:'\u2602',fitzpatrick_scale:!1,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:'\u2614',fitzpatrick_scale:!1,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:'\u{1f4a7}',fitzpatrick_scale:!1,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:'\u{1f4a6}',fitzpatrick_scale:!1,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:'\u{1f30a}',fitzpatrick_scale:!1,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:'\u{1f34f}',fitzpatrick_scale:!1,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:'\u{1f34e}',fitzpatrick_scale:!1,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:'\u{1f350}',fitzpatrick_scale:!1,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:'\u{1f34a}',fitzpatrick_scale:!1,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:'\u{1f34b}',fitzpatrick_scale:!1,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:'\u{1f34c}',fitzpatrick_scale:!1,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:'\u{1f349}',fitzpatrick_scale:!1,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:'\u{1f347}',fitzpatrick_scale:!1,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:'\u{1f353}',fitzpatrick_scale:!1,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:'\u{1f348}',fitzpatrick_scale:!1,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:'\u{1f352}',fitzpatrick_scale:!1,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:'\u{1f351}',fitzpatrick_scale:!1,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:'\u{1f34d}',fitzpatrick_scale:!1,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:'\u{1f965}',fitzpatrick_scale:!1,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:'\u{1f95d}',fitzpatrick_scale:!1,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:'\u{1f96d}',fitzpatrick_scale:!1,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:'\u{1f951}',fitzpatrick_scale:!1,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:'\u{1f966}',fitzpatrick_scale:!1,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:'\u{1f345}',fitzpatrick_scale:!1,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:'\u{1f346}',fitzpatrick_scale:!1,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:'\u{1f952}',fitzpatrick_scale:!1,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:'\u{1f955}',fitzpatrick_scale:!1,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:'\u{1f336}',fitzpatrick_scale:!1,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:'\u{1f954}',fitzpatrick_scale:!1,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:'\u{1f33d}',fitzpatrick_scale:!1,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:'\u{1f96c}',fitzpatrick_scale:!1,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:'\u{1f360}',fitzpatrick_scale:!1,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:'\u{1f95c}',fitzpatrick_scale:!1,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:'\u{1f36f}',fitzpatrick_scale:!1,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:'\u{1f950}',fitzpatrick_scale:!1,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:'\u{1f35e}',fitzpatrick_scale:!1,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:'\u{1f956}',fitzpatrick_scale:!1,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:'\u{1f96f}',fitzpatrick_scale:!1,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:'\u{1f968}',fitzpatrick_scale:!1,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:'\u{1f9c0}',fitzpatrick_scale:!1,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:'\u{1f95a}',fitzpatrick_scale:!1,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:'\u{1f953}',fitzpatrick_scale:!1,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:'\u{1f969}',fitzpatrick_scale:!1,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:'\u{1f95e}',fitzpatrick_scale:!1,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:'\u{1f357}',fitzpatrick_scale:!1,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:'\u{1f356}',fitzpatrick_scale:!1,category:"food_and_drink"},bone:{keywords:["skeleton"],char:'\u{1f9b4}',fitzpatrick_scale:!1,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:'\u{1f364}',fitzpatrick_scale:!1,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:'\u{1f373}',fitzpatrick_scale:!1,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:'\u{1f354}',fitzpatrick_scale:!1,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:'\u{1f35f}',fitzpatrick_scale:!1,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:'\u{1f959}',fitzpatrick_scale:!1,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:'\u{1f32d}',fitzpatrick_scale:!1,category:"food_and_drink"},pizza:{keywords:["food","party"],char:'\u{1f355}',fitzpatrick_scale:!1,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:'\u{1f96a}',fitzpatrick_scale:!1,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:'\u{1f96b}',fitzpatrick_scale:!1,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:'\u{1f35d}',fitzpatrick_scale:!1,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:'\u{1f32e}',fitzpatrick_scale:!1,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:'\u{1f32f}',fitzpatrick_scale:!1,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:'\u{1f957}',fitzpatrick_scale:!1,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:'\u{1f958}',fitzpatrick_scale:!1,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:'\u{1f35c}',fitzpatrick_scale:!1,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:'\u{1f372}',fitzpatrick_scale:!1,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:'\u{1f365}',fitzpatrick_scale:!1,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:'\u{1f960}',fitzpatrick_scale:!1,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:'\u{1f363}',fitzpatrick_scale:!1,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:'\u{1f371}',fitzpatrick_scale:!1,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:'\u{1f35b}',fitzpatrick_scale:!1,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:'\u{1f359}',fitzpatrick_scale:!1,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:'\u{1f35a}',fitzpatrick_scale:!1,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:'\u{1f358}',fitzpatrick_scale:!1,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:'\u{1f362}',fitzpatrick_scale:!1,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:'\u{1f361}',fitzpatrick_scale:!1,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:'\u{1f367}',fitzpatrick_scale:!1,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:'\u{1f368}',fitzpatrick_scale:!1,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:'\u{1f366}',fitzpatrick_scale:!1,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:'\u{1f967}',fitzpatrick_scale:!1,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:'\u{1f370}',fitzpatrick_scale:!1,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:'\u{1f9c1}',fitzpatrick_scale:!1,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:'\u{1f96e}',fitzpatrick_scale:!1,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:'\u{1f382}',fitzpatrick_scale:!1,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:'\u{1f36e}',fitzpatrick_scale:!1,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:'\u{1f36c}',fitzpatrick_scale:!1,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:'\u{1f36d}',fitzpatrick_scale:!1,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:'\u{1f36b}',fitzpatrick_scale:!1,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:'\u{1f37f}',fitzpatrick_scale:!1,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:'\u{1f95f}',fitzpatrick_scale:!1,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:'\u{1f369}',fitzpatrick_scale:!1,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:'\u{1f36a}',fitzpatrick_scale:!1,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:'\u{1f95b}',fitzpatrick_scale:!1,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'\u{1f37a}',fitzpatrick_scale:!1,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'\u{1f37b}',fitzpatrick_scale:!1,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:'\u{1f942}',fitzpatrick_scale:!1,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:'\u{1f377}',fitzpatrick_scale:!1,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:'\u{1f943}',fitzpatrick_scale:!1,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:'\u{1f378}',fitzpatrick_scale:!1,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:'\u{1f379}',fitzpatrick_scale:!1,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:'\u{1f37e}',fitzpatrick_scale:!1,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:'\u{1f376}',fitzpatrick_scale:!1,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:'\u{1f375}',fitzpatrick_scale:!1,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:'\u{1f964}',fitzpatrick_scale:!1,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:'\u2615',fitzpatrick_scale:!1,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:'\u{1f37c}',fitzpatrick_scale:!1,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:'\u{1f9c2}',fitzpatrick_scale:!1,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:'\u{1f944}',fitzpatrick_scale:!1,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:'\u{1f374}',fitzpatrick_scale:!1,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:'\u{1f37d}',fitzpatrick_scale:!1,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:'\u{1f963}',fitzpatrick_scale:!1,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:'\u{1f961}',fitzpatrick_scale:!1,category:"food_and_drink"},chopsticks:{keywords:["food"],char:'\u{1f962}',fitzpatrick_scale:!1,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:'\u26bd',fitzpatrick_scale:!1,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:'\u{1f3c0}',fitzpatrick_scale:!1,category:"activity"},football:{keywords:["sports","balls","NFL"],char:'\u{1f3c8}',fitzpatrick_scale:!1,category:"activity"},baseball:{keywords:["sports","balls"],char:'\u26be',fitzpatrick_scale:!1,category:"activity"},softball:{keywords:["sports","balls"],char:'\u{1f94e}',fitzpatrick_scale:!1,category:"activity"},tennis:{keywords:["sports","balls","green"],char:'\u{1f3be}',fitzpatrick_scale:!1,category:"activity"},volleyball:{keywords:["sports","balls"],char:'\u{1f3d0}',fitzpatrick_scale:!1,category:"activity"},rugby_football:{keywords:["sports","team"],char:'\u{1f3c9}',fitzpatrick_scale:!1,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:'\u{1f94f}',fitzpatrick_scale:!1,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:'\u{1f3b1}',fitzpatrick_scale:!1,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:'\u26f3',fitzpatrick_scale:!1,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:'\u{1f3cc}\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"activity"},golfing_man:{keywords:["sports","business"],char:'\u{1f3cc}',fitzpatrick_scale:!0,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:'\u{1f3d3}',fitzpatrick_scale:!1,category:"activity"},badminton:{keywords:["sports"],char:'\u{1f3f8}',fitzpatrick_scale:!1,category:"activity"},goal_net:{keywords:["sports"],char:'\u{1f945}',fitzpatrick_scale:!1,category:"activity"},ice_hockey:{keywords:["sports"],char:'\u{1f3d2}',fitzpatrick_scale:!1,category:"activity"},field_hockey:{keywords:["sports"],char:'\u{1f3d1}',fitzpatrick_scale:!1,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:'\u{1f94d}',fitzpatrick_scale:!1,category:"activity"},cricket:{keywords:["sports"],char:'\u{1f3cf}',fitzpatrick_scale:!1,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:'\u{1f3bf}',fitzpatrick_scale:!1,category:"activity"},skier:{keywords:["sports","winter","snow"],char:'\u26f7',fitzpatrick_scale:!1,category:"activity"},snowboarder:{keywords:["sports","winter"],char:'\u{1f3c2}',fitzpatrick_scale:!0,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:'\u{1f93a}',fitzpatrick_scale:!1,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:'\u{1f93c}\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:'\u{1f93c}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:'\u{1f938}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:'\u{1f938}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},woman_playing_handball:{keywords:["sports"],char:'\u{1f93e}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_playing_handball:{keywords:["sports"],char:'\u{1f93e}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},ice_skate:{keywords:["sports"],char:'\u26f8',fitzpatrick_scale:!1,category:"activity"},curling_stone:{keywords:["sports"],char:'\u{1f94c}',fitzpatrick_scale:!1,category:"activity"},skateboard:{keywords:["board"],char:'\u{1f6f9}',fitzpatrick_scale:!1,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:'\u{1f6f7}',fitzpatrick_scale:!1,category:"activity"},bow_and_arrow:{keywords:["sports"],char:'\u{1f3f9}',fitzpatrick_scale:!1,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:'\u{1f3a3}',fitzpatrick_scale:!1,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:'\u{1f94a}',fitzpatrick_scale:!1,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:'\u{1f94b}',fitzpatrick_scale:!1,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:'\u{1f6a3}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:'\u{1f6a3}',fitzpatrick_scale:!0,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:'\u{1f9d7}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:'\u{1f9d7}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:'\u{1f3ca}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:'\u{1f3ca}',fitzpatrick_scale:!0,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:'\u{1f93d}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:'\u{1f93d}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:'\u{1f9d8}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:'\u{1f9d8}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:'\u{1f3c4}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:'\u{1f3c4}',fitzpatrick_scale:!0,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:'\u{1f6c0}',fitzpatrick_scale:!0,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:'\u26f9\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},basketball_man:{keywords:["sports","human"],char:'\u26f9',fitzpatrick_scale:!0,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:'\u{1f3cb}\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:'\u{1f3cb}',fitzpatrick_scale:!0,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:'\u{1f6b4}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:'\u{1f6b4}',fitzpatrick_scale:!0,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:'\u{1f6b5}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:'\u{1f6b5}',fitzpatrick_scale:!0,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:'\u{1f3c7}',fitzpatrick_scale:!0,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:'\u{1f574}',fitzpatrick_scale:!0,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:'\u{1f3c6}',fitzpatrick_scale:!1,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:'\u{1f3bd}',fitzpatrick_scale:!1,category:"activity"},medal_sports:{keywords:["award","winning"],char:'\u{1f3c5}',fitzpatrick_scale:!1,category:"activity"},medal_military:{keywords:["award","winning","army"],char:'\u{1f396}',fitzpatrick_scale:!1,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:'\u{1f947}',fitzpatrick_scale:!1,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:'\u{1f948}',fitzpatrick_scale:!1,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:'\u{1f949}',fitzpatrick_scale:!1,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:'\u{1f397}',fitzpatrick_scale:!1,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:'\u{1f3f5}',fitzpatrick_scale:!1,category:"activity"},ticket:{keywords:["event","concert","pass"],char:'\u{1f3ab}',fitzpatrick_scale:!1,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:'\u{1f39f}',fitzpatrick_scale:!1,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:'\u{1f3ad}',fitzpatrick_scale:!1,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:'\u{1f3a8}',fitzpatrick_scale:!1,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:'\u{1f3aa}',fitzpatrick_scale:!1,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:'\u{1f939}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:'\u{1f939}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:'\u{1f3a4}',fitzpatrick_scale:!1,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:'\u{1f3a7}',fitzpatrick_scale:!1,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:'\u{1f3bc}',fitzpatrick_scale:!1,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:'\u{1f3b9}',fitzpatrick_scale:!1,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:'\u{1f941}',fitzpatrick_scale:!1,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:'\u{1f3b7}',fitzpatrick_scale:!1,category:"activity"},trumpet:{keywords:["music","brass"],char:'\u{1f3ba}',fitzpatrick_scale:!1,category:"activity"},guitar:{keywords:["music","instrument"],char:'\u{1f3b8}',fitzpatrick_scale:!1,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:'\u{1f3bb}',fitzpatrick_scale:!1,category:"activity"},clapper:{keywords:["movie","film","record"],char:'\u{1f3ac}',fitzpatrick_scale:!1,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:'\u{1f3ae}',fitzpatrick_scale:!1,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:'\u{1f47e}',fitzpatrick_scale:!1,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:'\u{1f3af}',fitzpatrick_scale:!1,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:'\u{1f3b2}',fitzpatrick_scale:!1,category:"activity"},chess_pawn:{keywords:["expendable"],char:"\u265f",fitzpatrick_scale:!1,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:'\u{1f3b0}',fitzpatrick_scale:!1,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:'\u{1f9e9}',fitzpatrick_scale:!1,category:"activity"},bowling:{keywords:["sports","fun","play"],char:'\u{1f3b3}',fitzpatrick_scale:!1,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:'\u{1f697}',fitzpatrick_scale:!1,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:'\u{1f695}',fitzpatrick_scale:!1,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:'\u{1f699}',fitzpatrick_scale:!1,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:'\u{1f68c}',fitzpatrick_scale:!1,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:'\u{1f68e}',fitzpatrick_scale:!1,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:'\u{1f3ce}',fitzpatrick_scale:!1,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:'\u{1f693}',fitzpatrick_scale:!1,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:'\u{1f691}',fitzpatrick_scale:!1,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:'\u{1f692}',fitzpatrick_scale:!1,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:'\u{1f690}',fitzpatrick_scale:!1,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:'\u{1f69a}',fitzpatrick_scale:!1,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:'\u{1f69b}',fitzpatrick_scale:!1,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:'\u{1f69c}',fitzpatrick_scale:!1,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:'\u{1f6f4}',fitzpatrick_scale:!1,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:'\u{1f3cd}',fitzpatrick_scale:!1,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:'\u{1f6b2}',fitzpatrick_scale:!1,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:'\u{1f6f5}',fitzpatrick_scale:!1,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:'\u{1f6a8}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:'\u{1f694}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:'\u{1f68d}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:'\u{1f698}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:'\u{1f696}',fitzpatrick_scale:!1,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:'\u{1f6a1}',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:'\u{1f6a0}',fitzpatrick_scale:!1,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:'\u{1f69f}',fitzpatrick_scale:!1,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:'\u{1f683}',fitzpatrick_scale:!1,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:'\u{1f68b}',fitzpatrick_scale:!1,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:'\u{1f69d}',fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:'\u{1f684}',fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:'\u{1f685}',fitzpatrick_scale:!1,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:'\u{1f688}',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:'\u{1f69e}',fitzpatrick_scale:!1,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:'\u{1f682}',fitzpatrick_scale:!1,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:'\u{1f686}',fitzpatrick_scale:!1,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:'\u{1f687}',fitzpatrick_scale:!1,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:'\u{1f68a}',fitzpatrick_scale:!1,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:'\u{1f689}',fitzpatrick_scale:!1,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:'\u{1f6f8}',fitzpatrick_scale:!1,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:'\u{1f681}',fitzpatrick_scale:!1,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:'\u{1f6e9}',fitzpatrick_scale:!1,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:'\u2708\ufe0f',fitzpatrick_scale:!1,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:'\u{1f6eb}',fitzpatrick_scale:!1,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:'\u{1f6ec}',fitzpatrick_scale:!1,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:'\u26f5',fitzpatrick_scale:!1,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:'\u{1f6e5}',fitzpatrick_scale:!1,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:'\u{1f6a4}',fitzpatrick_scale:!1,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:'\u26f4',fitzpatrick_scale:!1,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:'\u{1f6f3}',fitzpatrick_scale:!1,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:'\u{1f680}',fitzpatrick_scale:!1,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:'\u{1f6f0}',fitzpatrick_scale:!1,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:'\u{1f4ba}',fitzpatrick_scale:!1,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:'\u{1f6f6}',fitzpatrick_scale:!1,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:'\u2693',fitzpatrick_scale:!1,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:'\u{1f6a7}',fitzpatrick_scale:!1,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:'\u26fd',fitzpatrick_scale:!1,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:'\u{1f68f}',fitzpatrick_scale:!1,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:'\u{1f6a6}',fitzpatrick_scale:!1,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:'\u{1f6a5}',fitzpatrick_scale:!1,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:'\u{1f3c1}',fitzpatrick_scale:!1,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:'\u{1f6a2}',fitzpatrick_scale:!1,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:'\u{1f3a1}',fitzpatrick_scale:!1,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:'\u{1f3a2}',fitzpatrick_scale:!1,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:'\u{1f3a0}',fitzpatrick_scale:!1,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:'\u{1f3d7}',fitzpatrick_scale:!1,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:'\u{1f301}',fitzpatrick_scale:!1,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:'\u{1f5fc}',fitzpatrick_scale:!1,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:'\u{1f3ed}',fitzpatrick_scale:!1,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:'\u26f2',fitzpatrick_scale:!1,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:'\u{1f391}',fitzpatrick_scale:!1,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:'\u26f0',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:'\u{1f3d4}',fitzpatrick_scale:!1,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:'\u{1f5fb}',fitzpatrick_scale:!1,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:'\u{1f30b}',fitzpatrick_scale:!1,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:'\u{1f5fe}',fitzpatrick_scale:!1,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:'\u{1f3d5}',fitzpatrick_scale:!1,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:'\u26fa',fitzpatrick_scale:!1,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:'\u{1f3de}',fitzpatrick_scale:!1,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:'\u{1f6e3}',fitzpatrick_scale:!1,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:'\u{1f6e4}',fitzpatrick_scale:!1,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:'\u{1f305}',fitzpatrick_scale:!1,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:'\u{1f304}',fitzpatrick_scale:!1,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:'\u{1f3dc}',fitzpatrick_scale:!1,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:'\u{1f3d6}',fitzpatrick_scale:!1,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:'\u{1f3dd}',fitzpatrick_scale:!1,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:'\u{1f307}',fitzpatrick_scale:!1,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:'\u{1f306}',fitzpatrick_scale:!1,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:'\u{1f3d9}',fitzpatrick_scale:!1,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:'\u{1f303}',fitzpatrick_scale:!1,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:'\u{1f309}',fitzpatrick_scale:!1,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:'\u{1f30c}',fitzpatrick_scale:!1,category:"travel_and_places"},stars:{keywords:["night","photo"],char:'\u{1f320}',fitzpatrick_scale:!1,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:'\u{1f387}',fitzpatrick_scale:!1,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:'\u{1f386}',fitzpatrick_scale:!1,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:'\u{1f308}',fitzpatrick_scale:!1,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:'\u{1f3d8}',fitzpatrick_scale:!1,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:'\u{1f3f0}',fitzpatrick_scale:!1,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:'\u{1f3ef}',fitzpatrick_scale:!1,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:'\u{1f3df}',fitzpatrick_scale:!1,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:'\u{1f5fd}',fitzpatrick_scale:!1,category:"travel_and_places"},house:{keywords:["building","home"],char:'\u{1f3e0}',fitzpatrick_scale:!1,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:'\u{1f3e1}',fitzpatrick_scale:!1,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:'\u{1f3da}',fitzpatrick_scale:!1,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:'\u{1f3e2}',fitzpatrick_scale:!1,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:'\u{1f3ec}',fitzpatrick_scale:!1,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:'\u{1f3e3}',fitzpatrick_scale:!1,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:'\u{1f3e4}',fitzpatrick_scale:!1,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:'\u{1f3e5}',fitzpatrick_scale:!1,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:'\u{1f3e6}',fitzpatrick_scale:!1,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:'\u{1f3e8}',fitzpatrick_scale:!1,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:'\u{1f3ea}',fitzpatrick_scale:!1,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:'\u{1f3eb}',fitzpatrick_scale:!1,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:'\u{1f3e9}',fitzpatrick_scale:!1,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:'\u{1f492}',fitzpatrick_scale:!1,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:'\u{1f3db}',fitzpatrick_scale:!1,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:'\u26ea',fitzpatrick_scale:!1,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:'\u{1f54c}',fitzpatrick_scale:!1,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:'\u{1f54d}',fitzpatrick_scale:!1,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:'\u{1f54b}',fitzpatrick_scale:!1,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:'\u26e9',fitzpatrick_scale:!1,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:'\u231a',fitzpatrick_scale:!1,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:'\u{1f4f1}',fitzpatrick_scale:!1,category:"objects"},calling:{keywords:["iphone","incoming"],char:'\u{1f4f2}',fitzpatrick_scale:!1,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:'\u{1f4bb}',fitzpatrick_scale:!1,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:'\u2328',fitzpatrick_scale:!1,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:'\u{1f5a5}',fitzpatrick_scale:!1,category:"objects"},printer:{keywords:["paper","ink"],char:'\u{1f5a8}',fitzpatrick_scale:!1,category:"objects"},computer_mouse:{keywords:["click"],char:'\u{1f5b1}',fitzpatrick_scale:!1,category:"objects"},trackball:{keywords:["technology","trackpad"],char:'\u{1f5b2}',fitzpatrick_scale:!1,category:"objects"},joystick:{keywords:["game","play"],char:'\u{1f579}',fitzpatrick_scale:!1,category:"objects"},clamp:{keywords:["tool"],char:'\u{1f5dc}',fitzpatrick_scale:!1,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:'\u{1f4bd}',fitzpatrick_scale:!1,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:'\u{1f4be}',fitzpatrick_scale:!1,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:'\u{1f4bf}',fitzpatrick_scale:!1,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:'\u{1f4c0}',fitzpatrick_scale:!1,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:'\u{1f4fc}',fitzpatrick_scale:!1,category:"objects"},camera:{keywords:["gadgets","photography"],char:'\u{1f4f7}',fitzpatrick_scale:!1,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:'\u{1f4f8}',fitzpatrick_scale:!1,category:"objects"},video_camera:{keywords:["film","record"],char:'\u{1f4f9}',fitzpatrick_scale:!1,category:"objects"},movie_camera:{keywords:["film","record"],char:'\u{1f3a5}',fitzpatrick_scale:!1,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:'\u{1f4fd}',fitzpatrick_scale:!1,category:"objects"},film_strip:{keywords:["movie"],char:'\u{1f39e}',fitzpatrick_scale:!1,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:'\u{1f4de}',fitzpatrick_scale:!1,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:'\u260e\ufe0f',fitzpatrick_scale:!1,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:'\u{1f4df}',fitzpatrick_scale:!1,category:"objects"},fax:{keywords:["communication","technology"],char:'\u{1f4e0}',fitzpatrick_scale:!1,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:'\u{1f4fa}',fitzpatrick_scale:!1,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:'\u{1f4fb}',fitzpatrick_scale:!1,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:'\u{1f399}',fitzpatrick_scale:!1,category:"objects"},level_slider:{keywords:["scale"],char:'\u{1f39a}',fitzpatrick_scale:!1,category:"objects"},control_knobs:{keywords:["dial"],char:'\u{1f39b}',fitzpatrick_scale:!1,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:'\u{1f9ed}',fitzpatrick_scale:!1,category:"objects"},stopwatch:{keywords:["time","deadline"],char:'\u23f1',fitzpatrick_scale:!1,category:"objects"},timer_clock:{keywords:["alarm"],char:'\u23f2',fitzpatrick_scale:!1,category:"objects"},alarm_clock:{keywords:["time","wake"],char:'\u23f0',fitzpatrick_scale:!1,category:"objects"},mantelpiece_clock:{keywords:["time"],char:'\u{1f570}',fitzpatrick_scale:!1,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:'\u23f3',fitzpatrick_scale:!1,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:'\u231b',fitzpatrick_scale:!1,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:'\u{1f4e1}',fitzpatrick_scale:!1,category:"objects"},battery:{keywords:["power","energy","sustain"],char:'\u{1f50b}',fitzpatrick_scale:!1,category:"objects"},electric_plug:{keywords:["charger","power"],char:'\u{1f50c}',fitzpatrick_scale:!1,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:'\u{1f4a1}',fitzpatrick_scale:!1,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:'\u{1f526}',fitzpatrick_scale:!1,category:"objects"},candle:{keywords:["fire","wax"],char:'\u{1f56f}',fitzpatrick_scale:!1,category:"objects"},fire_extinguisher:{keywords:["quench"],char:'\u{1f9ef}',fitzpatrick_scale:!1,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:'\u{1f5d1}',fitzpatrick_scale:!1,category:"objects"},oil_drum:{keywords:["barrell"],char:'\u{1f6e2}',fitzpatrick_scale:!1,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:'\u{1f4b8}',fitzpatrick_scale:!1,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:'\u{1f4b5}',fitzpatrick_scale:!1,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:'\u{1f4b4}',fitzpatrick_scale:!1,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:'\u{1f4b6}',fitzpatrick_scale:!1,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:'\u{1f4b7}',fitzpatrick_scale:!1,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:'\u{1f4b0}',fitzpatrick_scale:!1,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:'\u{1f4b3}',fitzpatrick_scale:!1,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:'\u{1f48e}',fitzpatrick_scale:!1,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:'\u2696',fitzpatrick_scale:!1,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:'\u{1f9f0}',fitzpatrick_scale:!1,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:'\u{1f527}',fitzpatrick_scale:!1,category:"objects"},hammer:{keywords:["tools","build","create"],char:'\u{1f528}',fitzpatrick_scale:!1,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:'\u2692',fitzpatrick_scale:!1,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:'\u{1f6e0}',fitzpatrick_scale:!1,category:"objects"},pick:{keywords:["tools","dig"],char:'\u26cf',fitzpatrick_scale:!1,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:'\u{1f529}',fitzpatrick_scale:!1,category:"objects"},gear:{keywords:["cog"],char:'\u2699',fitzpatrick_scale:!1,category:"objects"},brick:{keywords:["bricks"],char:'\u{1f9f1}',fitzpatrick_scale:!1,category:"objects"},chains:{keywords:["lock","arrest"],char:'\u26d3',fitzpatrick_scale:!1,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:'\u{1f9f2}',fitzpatrick_scale:!1,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:'\u{1f52b}',fitzpatrick_scale:!1,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:'\u{1f4a3}',fitzpatrick_scale:!1,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:'\u{1f9e8}',fitzpatrick_scale:!1,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:'\u{1f52a}',fitzpatrick_scale:!1,category:"objects"},dagger:{keywords:["weapon"],char:'\u{1f5e1}',fitzpatrick_scale:!1,category:"objects"},crossed_swords:{keywords:["weapon"],char:'\u2694',fitzpatrick_scale:!1,category:"objects"},shield:{keywords:["protection","security"],char:'\u{1f6e1}',fitzpatrick_scale:!1,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:'\u{1f6ac}',fitzpatrick_scale:!1,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:'\u2620',fitzpatrick_scale:!1,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:'\u26b0',fitzpatrick_scale:!1,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:'\u26b1',fitzpatrick_scale:!1,category:"objects"},amphora:{keywords:["vase","jar"],char:'\u{1f3fa}',fitzpatrick_scale:!1,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:'\u{1f52e}',fitzpatrick_scale:!1,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:'\u{1f4ff}',fitzpatrick_scale:!1,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:'\u{1f9ff}',fitzpatrick_scale:!1,category:"objects"},barber:{keywords:["hair","salon","style"],char:'\u{1f488}',fitzpatrick_scale:!1,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:'\u2697',fitzpatrick_scale:!1,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:'\u{1f52d}',fitzpatrick_scale:!1,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:'\u{1f52c}',fitzpatrick_scale:!1,category:"objects"},hole:{keywords:["embarrassing"],char:'\u{1f573}',fitzpatrick_scale:!1,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:'\u{1f48a}',fitzpatrick_scale:!1,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:'\u{1f489}',fitzpatrick_scale:!1,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:'\u{1f9ec}',fitzpatrick_scale:!1,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:'\u{1f9a0}',fitzpatrick_scale:!1,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:'\u{1f9eb}',fitzpatrick_scale:!1,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:'\u{1f9ea}',fitzpatrick_scale:!1,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:'\u{1f321}',fitzpatrick_scale:!1,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:'\u{1f9f9}',fitzpatrick_scale:!1,category:"objects"},basket:{keywords:["laundry"],char:'\u{1f9fa}',fitzpatrick_scale:!1,category:"objects"},toilet_paper:{keywords:["roll"],char:'\u{1f9fb}',fitzpatrick_scale:!1,category:"objects"},label:{keywords:["sale","tag"],char:'\u{1f3f7}',fitzpatrick_scale:!1,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:'\u{1f516}',fitzpatrick_scale:!1,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:'\u{1f6bd}',fitzpatrick_scale:!1,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:'\u{1f6bf}',fitzpatrick_scale:!1,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:'\u{1f6c1}',fitzpatrick_scale:!1,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:'\u{1f9fc}',fitzpatrick_scale:!1,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:'\u{1f9fd}',fitzpatrick_scale:!1,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:'\u{1f9f4}',fitzpatrick_scale:!1,category:"objects"},key:{keywords:["lock","door","password"],char:'\u{1f511}',fitzpatrick_scale:!1,category:"objects"},old_key:{keywords:["lock","door","password"],char:'\u{1f5dd}',fitzpatrick_scale:!1,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:'\u{1f6cb}',fitzpatrick_scale:!1,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:'\u{1f6cc}',fitzpatrick_scale:!0,category:"objects"},bed:{keywords:["sleep","rest"],char:'\u{1f6cf}',fitzpatrick_scale:!1,category:"objects"},door:{keywords:["house","entry","exit"],char:'\u{1f6aa}',fitzpatrick_scale:!1,category:"objects"},bellhop_bell:{keywords:["service"],char:'\u{1f6ce}',fitzpatrick_scale:!1,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:'\u{1f9f8}',fitzpatrick_scale:!1,category:"objects"},framed_picture:{keywords:["photography"],char:'\u{1f5bc}',fitzpatrick_scale:!1,category:"objects"},world_map:{keywords:["location","direction"],char:'\u{1f5fa}',fitzpatrick_scale:!1,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:'\u26f1',fitzpatrick_scale:!1,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:'\u{1f5ff}',fitzpatrick_scale:!1,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:'\u{1f6cd}',fitzpatrick_scale:!1,category:"objects"},shopping_cart:{keywords:["trolley"],char:'\u{1f6d2}',fitzpatrick_scale:!1,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:'\u{1f388}',fitzpatrick_scale:!1,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:'\u{1f38f}',fitzpatrick_scale:!1,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:'\u{1f380}',fitzpatrick_scale:!1,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:'\u{1f381}',fitzpatrick_scale:!1,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:'\u{1f38a}',fitzpatrick_scale:!1,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:'\u{1f389}',fitzpatrick_scale:!1,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:'\u{1f38e}',fitzpatrick_scale:!1,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:'\u{1f390}',fitzpatrick_scale:!1,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:'\u{1f38c}',fitzpatrick_scale:!1,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:'\u{1f3ee}',fitzpatrick_scale:!1,category:"objects"},red_envelope:{keywords:["gift"],char:'\u{1f9e7}',fitzpatrick_scale:!1,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:'\u2709\ufe0f',fitzpatrick_scale:!1,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:'\u{1f4e9}',fitzpatrick_scale:!1,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:'\u{1f4e8}',fitzpatrick_scale:!1,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:'\u{1f4e7}',fitzpatrick_scale:!1,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:'\u{1f48c}',fitzpatrick_scale:!1,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:'\u{1f4ee}',fitzpatrick_scale:!1,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:'\u{1f4ea}',fitzpatrick_scale:!1,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:'\u{1f4eb}',fitzpatrick_scale:!1,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:'\u{1f4ec}',fitzpatrick_scale:!1,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:'\u{1f4ed}',fitzpatrick_scale:!1,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:'\u{1f4e6}',fitzpatrick_scale:!1,category:"objects"},postal_horn:{keywords:["instrument","music"],char:'\u{1f4ef}',fitzpatrick_scale:!1,category:"objects"},inbox_tray:{keywords:["email","documents"],char:'\u{1f4e5}',fitzpatrick_scale:!1,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:'\u{1f4e4}',fitzpatrick_scale:!1,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:'\u{1f4dc}',fitzpatrick_scale:!1,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:'\u{1f4c3}',fitzpatrick_scale:!1,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:'\u{1f4d1}',fitzpatrick_scale:!1,category:"objects"},receipt:{keywords:["accounting","expenses"],char:'\u{1f9fe}',fitzpatrick_scale:!1,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:'\u{1f4ca}',fitzpatrick_scale:!1,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:'\u{1f4c8}',fitzpatrick_scale:!1,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:'\u{1f4c9}',fitzpatrick_scale:!1,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:'\u{1f4c4}',fitzpatrick_scale:!1,category:"objects"},date:{keywords:["calendar","schedule"],char:'\u{1f4c5}',fitzpatrick_scale:!1,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:'\u{1f4c6}',fitzpatrick_scale:!1,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:'\u{1f5d3}',fitzpatrick_scale:!1,category:"objects"},card_index:{keywords:["business","stationery"],char:'\u{1f4c7}',fitzpatrick_scale:!1,category:"objects"},card_file_box:{keywords:["business","stationery"],char:'\u{1f5c3}',fitzpatrick_scale:!1,category:"objects"},ballot_box:{keywords:["election","vote"],char:'\u{1f5f3}',fitzpatrick_scale:!1,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:'\u{1f5c4}',fitzpatrick_scale:!1,category:"objects"},clipboard:{keywords:["stationery","documents"],char:'\u{1f4cb}',fitzpatrick_scale:!1,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:'\u{1f5d2}',fitzpatrick_scale:!1,category:"objects"},file_folder:{keywords:["documents","business","office"],char:'\u{1f4c1}',fitzpatrick_scale:!1,category:"objects"},open_file_folder:{keywords:["documents","load"],char:'\u{1f4c2}',fitzpatrick_scale:!1,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:'\u{1f5c2}',fitzpatrick_scale:!1,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:'\u{1f5de}',fitzpatrick_scale:!1,category:"objects"},newspaper:{keywords:["press","headline"],char:'\u{1f4f0}',fitzpatrick_scale:!1,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:'\u{1f4d3}',fitzpatrick_scale:!1,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:'\u{1f4d5}',fitzpatrick_scale:!1,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:'\u{1f4d7}',fitzpatrick_scale:!1,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:'\u{1f4d8}',fitzpatrick_scale:!1,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:'\u{1f4d9}',fitzpatrick_scale:!1,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:'\u{1f4d4}',fitzpatrick_scale:!1,category:"objects"},ledger:{keywords:["notes","paper"],char:'\u{1f4d2}',fitzpatrick_scale:!1,category:"objects"},books:{keywords:["literature","library","study"],char:'\u{1f4da}',fitzpatrick_scale:!1,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:'\u{1f4d6}',fitzpatrick_scale:!1,category:"objects"},safety_pin:{keywords:["diaper"],char:'\u{1f9f7}',fitzpatrick_scale:!1,category:"objects"},link:{keywords:["rings","url"],char:'\u{1f517}',fitzpatrick_scale:!1,category:"objects"},paperclip:{keywords:["documents","stationery"],char:'\u{1f4ce}',fitzpatrick_scale:!1,category:"objects"},paperclips:{keywords:["documents","stationery"],char:'\u{1f587}',fitzpatrick_scale:!1,category:"objects"},scissors:{keywords:["stationery","cut"],char:'\u2702\ufe0f',fitzpatrick_scale:!1,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:'\u{1f4d0}',fitzpatrick_scale:!1,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:'\u{1f4cf}',fitzpatrick_scale:!1,category:"objects"},abacus:{keywords:["calculation"],char:'\u{1f9ee}',fitzpatrick_scale:!1,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:'\u{1f4cc}',fitzpatrick_scale:!1,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:'\u{1f4cd}',fitzpatrick_scale:!1,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:'\u{1f6a9}',fitzpatrick_scale:!1,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:'\u{1f3f3}',fitzpatrick_scale:!1,category:"objects"},black_flag:{keywords:["pirate"],char:'\u{1f3f4}',fitzpatrick_scale:!1,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:'\u{1f3f3}\ufe0f\u200d\u{1f308}',fitzpatrick_scale:!1,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:'\u{1f510}',fitzpatrick_scale:!1,category:"objects"},lock:{keywords:["security","password","padlock"],char:'\u{1f512}',fitzpatrick_scale:!1,category:"objects"},unlock:{keywords:["privacy","security"],char:'\u{1f513}',fitzpatrick_scale:!1,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:'\u{1f50f}',fitzpatrick_scale:!1,category:"objects"},pen:{keywords:["stationery","writing","write"],char:'\u{1f58a}',fitzpatrick_scale:!1,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:'\u{1f58b}',fitzpatrick_scale:!1,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:'\u2712\ufe0f',fitzpatrick_scale:!1,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:'\u{1f4dd}',fitzpatrick_scale:!1,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:'\u270f\ufe0f',fitzpatrick_scale:!1,category:"objects"},crayon:{keywords:["drawing","creativity"],char:'\u{1f58d}',fitzpatrick_scale:!1,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:'\u{1f58c}',fitzpatrick_scale:!1,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:'\u{1f50d}',fitzpatrick_scale:!1,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:'\u{1f50e}',fitzpatrick_scale:!1,category:"objects"},heart:{keywords:["love","like","valentines"],char:'\u2764\ufe0f',fitzpatrick_scale:!1,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f9e1}',fitzpatrick_scale:!1,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f49b}',fitzpatrick_scale:!1,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f49a}',fitzpatrick_scale:!1,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f499}',fitzpatrick_scale:!1,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f49c}',fitzpatrick_scale:!1,category:"symbols"},black_heart:{keywords:["evil"],char:'\u{1f5a4}',fitzpatrick_scale:!1,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:'\u{1f494}',fitzpatrick_scale:!1,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:'\u2763',fitzpatrick_scale:!1,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:'\u{1f495}',fitzpatrick_scale:!1,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:'\u{1f49e}',fitzpatrick_scale:!1,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:'\u{1f493}',fitzpatrick_scale:!1,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:'\u{1f497}',fitzpatrick_scale:!1,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f496}',fitzpatrick_scale:!1,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:'\u{1f498}',fitzpatrick_scale:!1,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:'\u{1f49d}',fitzpatrick_scale:!1,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:'\u{1f49f}',fitzpatrick_scale:!1,category:"symbols"},peace_symbol:{keywords:["hippie"],char:'\u262e',fitzpatrick_scale:!1,category:"symbols"},latin_cross:{keywords:["christianity"],char:'\u271d',fitzpatrick_scale:!1,category:"symbols"},star_and_crescent:{keywords:["islam"],char:'\u262a',fitzpatrick_scale:!1,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'\u{1f549}',fitzpatrick_scale:!1,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'\u2638',fitzpatrick_scale:!1,category:"symbols"},star_of_david:{keywords:["judaism"],char:'\u2721',fitzpatrick_scale:!1,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:'\u{1f52f}',fitzpatrick_scale:!1,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:'\u{1f54e}',fitzpatrick_scale:!1,category:"symbols"},yin_yang:{keywords:["balance"],char:'\u262f',fitzpatrick_scale:!1,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:'\u2626',fitzpatrick_scale:!1,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:'\u{1f6d0}',fitzpatrick_scale:!1,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:'\u26ce',fitzpatrick_scale:!1,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u2648',fitzpatrick_scale:!1,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:'\u2649',fitzpatrick_scale:!1,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u264a',fitzpatrick_scale:!1,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u264b',fitzpatrick_scale:!1,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u264c',fitzpatrick_scale:!1,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u264d',fitzpatrick_scale:!1,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u264e',fitzpatrick_scale:!1,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:'\u264f',fitzpatrick_scale:!1,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u2650',fitzpatrick_scale:!1,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u2651',fitzpatrick_scale:!1,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u2652',fitzpatrick_scale:!1,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:'\u2653',fitzpatrick_scale:!1,category:"symbols"},id:{keywords:["purple-square","words"],char:'\u{1f194}',fitzpatrick_scale:!1,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:'\u269b',fitzpatrick_scale:!1,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:'\u{1f233}',fitzpatrick_scale:!1,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:'\u{1f239}',fitzpatrick_scale:!1,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:'\u2622',fitzpatrick_scale:!1,category:"symbols"},biohazard:{keywords:["danger"],char:'\u2623',fitzpatrick_scale:!1,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:'\u{1f4f4}',fitzpatrick_scale:!1,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:'\u{1f4f3}',fitzpatrick_scale:!1,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:'\u{1f236}',fitzpatrick_scale:!1,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:'\u{1f21a}',fitzpatrick_scale:!1,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:'\u{1f238}',fitzpatrick_scale:!1,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:'\u{1f23a}',fitzpatrick_scale:!1,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:'\u{1f237}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:'\u2734\ufe0f',fitzpatrick_scale:!1,category:"symbols"},vs:{keywords:["words","orange-square"],char:'\u{1f19a}',fitzpatrick_scale:!1,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:'\u{1f251}',fitzpatrick_scale:!1,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:'\u{1f4ae}',fitzpatrick_scale:!1,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:'\u{1f250}',fitzpatrick_scale:!1,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:'\u3299\ufe0f',fitzpatrick_scale:!1,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:'\u3297\ufe0f',fitzpatrick_scale:!1,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:'\u{1f234}',fitzpatrick_scale:!1,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:'\u{1f235}',fitzpatrick_scale:!1,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:'\u{1f232}',fitzpatrick_scale:!1,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:'\u{1f170}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:'\u{1f171}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:'\u{1f18e}',fitzpatrick_scale:!1,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:'\u{1f191}',fitzpatrick_scale:!1,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:'\u{1f17e}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:'\u{1f198}',fitzpatrick_scale:!1,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:'\u26d4',fitzpatrick_scale:!1,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:'\u{1f4db}',fitzpatrick_scale:!1,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:'\u{1f6ab}',fitzpatrick_scale:!1,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:'\u274c',fitzpatrick_scale:!1,category:"symbols"},o:{keywords:["circle","round"],char:'\u2b55',fitzpatrick_scale:!1,category:"symbols"},stop_sign:{keywords:["stop"],char:'\u{1f6d1}',fitzpatrick_scale:!1,category:"symbols"},anger:{keywords:["angry","mad"],char:'\u{1f4a2}',fitzpatrick_scale:!1,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:'\u2668\ufe0f',fitzpatrick_scale:!1,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:'\u{1f6b7}',fitzpatrick_scale:!1,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:'\u{1f6af}',fitzpatrick_scale:!1,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:'\u{1f6b3}',fitzpatrick_scale:!1,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:'\u{1f6b1}',fitzpatrick_scale:!1,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:'\u{1f51e}',fitzpatrick_scale:!1,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:'\u{1f4f5}',fitzpatrick_scale:!1,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:'\u2757',fitzpatrick_scale:!1,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:'\u2755',fitzpatrick_scale:!1,category:"symbols"},question:{keywords:["doubt","confused"],char:'\u2753',fitzpatrick_scale:!1,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:'\u2754',fitzpatrick_scale:!1,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:'\u203c\ufe0f',fitzpatrick_scale:!1,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:'\u2049\ufe0f',fitzpatrick_scale:!1,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:'\u{1f505}',fitzpatrick_scale:!1,category:"symbols"},high_brightness:{keywords:["sun","light"],char:'\u{1f506}',fitzpatrick_scale:!1,category:"symbols"},trident:{keywords:["weapon","spear"],char:'\u{1f531}',fitzpatrick_scale:!1,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:'\u269c',fitzpatrick_scale:!1,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:'\u303d\ufe0f',fitzpatrick_scale:!1,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:'\u26a0\ufe0f',fitzpatrick_scale:!1,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:'\u{1f6b8}',fitzpatrick_scale:!1,category:"symbols"},beginner:{keywords:["badge","shield"],char:'\u{1f530}',fitzpatrick_scale:!1,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:'\u267b\ufe0f',fitzpatrick_scale:!1,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:'\u{1f22f}',fitzpatrick_scale:!1,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:'\u{1f4b9}',fitzpatrick_scale:!1,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:'\u2747\ufe0f',fitzpatrick_scale:!1,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:'\u2733\ufe0f',fitzpatrick_scale:!1,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:'\u274e',fitzpatrick_scale:!1,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:'\u2705',fitzpatrick_scale:!1,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:'\u{1f4a0}',fitzpatrick_scale:!1,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:'\u{1f300}',fitzpatrick_scale:!1,category:"symbols"},loop:{keywords:["tape","cassette"],char:'\u27bf',fitzpatrick_scale:!1,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:'\u{1f310}',fitzpatrick_scale:!1,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:'\u24c2\ufe0f',fitzpatrick_scale:!1,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:'\u{1f3e7}',fitzpatrick_scale:!1,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:'\u{1f202}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:'\u{1f6c2}',fitzpatrick_scale:!1,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:'\u{1f6c3}',fitzpatrick_scale:!1,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:'\u{1f6c4}',fitzpatrick_scale:!1,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:'\u{1f6c5}',fitzpatrick_scale:!1,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:'\u267f',fitzpatrick_scale:!1,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:'\u{1f6ad}',fitzpatrick_scale:!1,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:'\u{1f6be}',fitzpatrick_scale:!1,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:'\u{1f17f}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:'\u{1f6b0}',fitzpatrick_scale:!1,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:'\u{1f6b9}',fitzpatrick_scale:!1,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:'\u{1f6ba}',fitzpatrick_scale:!1,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:'\u{1f6bc}',fitzpatrick_scale:!1,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:'\u{1f6bb}',fitzpatrick_scale:!1,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:'\u{1f6ae}',fitzpatrick_scale:!1,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:'\u{1f3a6}',fitzpatrick_scale:!1,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:'\u{1f4f6}',fitzpatrick_scale:!1,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:'\u{1f201}',fitzpatrick_scale:!1,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:'\u{1f196}',fitzpatrick_scale:!1,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:'\u{1f197}',fitzpatrick_scale:!1,category:"symbols"},up:{keywords:["blue-square","above","high"],char:'\u{1f199}',fitzpatrick_scale:!1,category:"symbols"},cool:{keywords:["words","blue-square"],char:'\u{1f192}',fitzpatrick_scale:!1,category:"symbols"},new:{keywords:["blue-square","words","start"],char:'\u{1f195}',fitzpatrick_scale:!1,category:"symbols"},free:{keywords:["blue-square","words"],char:'\u{1f193}',fitzpatrick_scale:!1,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:'0\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:'1\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:'2\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:'3\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:'4\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:'5\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:'6\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:'7\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:'8\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:'9\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:'\u{1f51f}',fitzpatrick_scale:!1,category:"symbols"},asterisk:{keywords:["star","keycap"],char:'*\u20e3',fitzpatrick_scale:!1,category:"symbols"},eject_button:{keywords:["blue-square"],char:'\u23cf\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:'\u25b6\ufe0f',fitzpatrick_scale:!1,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:'\u23f8',fitzpatrick_scale:!1,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:'\u23ed',fitzpatrick_scale:!1,category:"symbols"},stop_button:{keywords:["blue-square"],char:'\u23f9',fitzpatrick_scale:!1,category:"symbols"},record_button:{keywords:["blue-square"],char:'\u23fa',fitzpatrick_scale:!1,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:'\u23ef',fitzpatrick_scale:!1,category:"symbols"},previous_track_button:{keywords:["backward"],char:'\u23ee',fitzpatrick_scale:!1,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:'\u23e9',fitzpatrick_scale:!1,category:"symbols"},rewind:{keywords:["play","blue-square"],char:'\u23ea',fitzpatrick_scale:!1,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:'\u{1f500}',fitzpatrick_scale:!1,category:"symbols"},repeat:{keywords:["loop","record"],char:'\u{1f501}',fitzpatrick_scale:!1,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:'\u{1f502}',fitzpatrick_scale:!1,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:'\u25c0\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:'\u{1f53c}',fitzpatrick_scale:!1,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:'\u{1f53d}',fitzpatrick_scale:!1,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:'\u23eb',fitzpatrick_scale:!1,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:'\u23ec',fitzpatrick_scale:!1,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:'\u27a1\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:'\u2b05\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:'\u2b06\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:'\u2b07\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:'\u2197\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:'\u2198\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:'\u2199\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:'\u2196\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:'\u2195\ufe0f',fitzpatrick_scale:!1,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:'\u2194\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:'\u{1f504}',fitzpatrick_scale:!1,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:'\u21aa\ufe0f',fitzpatrick_scale:!1,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:'\u21a9\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:'\u2934\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:'\u2935\ufe0f',fitzpatrick_scale:!1,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:'#\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:'\u2139\ufe0f',fitzpatrick_scale:!1,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:'\u{1f524}',fitzpatrick_scale:!1,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:'\u{1f521}',fitzpatrick_scale:!1,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:'\u{1f520}',fitzpatrick_scale:!1,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:'\u{1f523}',fitzpatrick_scale:!1,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:'\u{1f3b5}',fitzpatrick_scale:!1,category:"symbols"},notes:{keywords:["music","score"],char:'\u{1f3b6}',fitzpatrick_scale:!1,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:'\u3030\ufe0f',fitzpatrick_scale:!1,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:'\u27b0',fitzpatrick_scale:!1,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:'\u2714\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:'\u{1f503}',fitzpatrick_scale:!1,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:'\u2795',fitzpatrick_scale:!1,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:'\u2796',fitzpatrick_scale:!1,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:'\u2797',fitzpatrick_scale:!1,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:'\u2716\ufe0f',fitzpatrick_scale:!1,category:"symbols"},infinity:{keywords:["forever"],char:'\u267e',fitzpatrick_scale:!1,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:'\u{1f4b2}',fitzpatrick_scale:!1,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:'\u{1f4b1}',fitzpatrick_scale:!1,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:'\xa9\ufe0f',fitzpatrick_scale:!1,category:"symbols"},registered:{keywords:["alphabet","circle"],char:'\xae\ufe0f',fitzpatrick_scale:!1,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:'\u2122\ufe0f',fitzpatrick_scale:!1,category:"symbols"},end:{keywords:["words","arrow"],char:'\u{1f51a}',fitzpatrick_scale:!1,category:"symbols"},back:{keywords:["arrow","words","return"],char:'\u{1f519}',fitzpatrick_scale:!1,category:"symbols"},on:{keywords:["arrow","words"],char:'\u{1f51b}',fitzpatrick_scale:!1,category:"symbols"},top:{keywords:["words","blue-square"],char:'\u{1f51d}',fitzpatrick_scale:!1,category:"symbols"},soon:{keywords:["arrow","words"],char:'\u{1f51c}',fitzpatrick_scale:!1,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:'\u2611\ufe0f',fitzpatrick_scale:!1,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:'\u{1f518}',fitzpatrick_scale:!1,category:"symbols"},white_circle:{keywords:["shape","round"],char:'\u26aa',fitzpatrick_scale:!1,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:'\u26ab',fitzpatrick_scale:!1,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:'\u{1f534}',fitzpatrick_scale:!1,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:'\u{1f535}',fitzpatrick_scale:!1,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f538}',fitzpatrick_scale:!1,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f539}',fitzpatrick_scale:!1,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f536}',fitzpatrick_scale:!1,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f537}',fitzpatrick_scale:!1,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:'\u{1f53a}',fitzpatrick_scale:!1,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:'\u25aa\ufe0f',fitzpatrick_scale:!1,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:'\u25ab\ufe0f',fitzpatrick_scale:!1,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:'\u2b1b',fitzpatrick_scale:!1,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:'\u2b1c',fitzpatrick_scale:!1,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:'\u{1f53b}',fitzpatrick_scale:!1,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:'\u25fc\ufe0f',fitzpatrick_scale:!1,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:'\u25fb\ufe0f',fitzpatrick_scale:!1,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:'\u25fe',fitzpatrick_scale:!1,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:'\u25fd',fitzpatrick_scale:!1,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:'\u{1f532}',fitzpatrick_scale:!1,category:"symbols"},white_square_button:{keywords:["shape","input"],char:'\u{1f533}',fitzpatrick_scale:!1,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:'\u{1f508}',fitzpatrick_scale:!1,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:'\u{1f509}',fitzpatrick_scale:!1,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:'\u{1f50a}',fitzpatrick_scale:!1,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:'\u{1f507}',fitzpatrick_scale:!1,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:'\u{1f4e3}',fitzpatrick_scale:!1,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:'\u{1f4e2}',fitzpatrick_scale:!1,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:'\u{1f514}',fitzpatrick_scale:!1,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:'\u{1f515}',fitzpatrick_scale:!1,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:'\u{1f0cf}',fitzpatrick_scale:!1,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:'\u{1f004}',fitzpatrick_scale:!1,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:'\u2660\ufe0f',fitzpatrick_scale:!1,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:'\u2663\ufe0f',fitzpatrick_scale:!1,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:'\u2665\ufe0f',fitzpatrick_scale:!1,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:'\u2666\ufe0f',fitzpatrick_scale:!1,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:'\u{1f3b4}',fitzpatrick_scale:!1,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:'\u{1f4ad}',fitzpatrick_scale:!1,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:'\u{1f5ef}',fitzpatrick_scale:!1,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:'\u{1f4ac}',fitzpatrick_scale:!1,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:'\u{1f5e8}',fitzpatrick_scale:!1,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:'\u{1f550}',fitzpatrick_scale:!1,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:'\u{1f551}',fitzpatrick_scale:!1,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:'\u{1f552}',fitzpatrick_scale:!1,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:'\u{1f553}',fitzpatrick_scale:!1,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:'\u{1f554}',fitzpatrick_scale:!1,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:'\u{1f555}',fitzpatrick_scale:!1,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:'\u{1f556}',fitzpatrick_scale:!1,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:'\u{1f557}',fitzpatrick_scale:!1,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:'\u{1f558}',fitzpatrick_scale:!1,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:'\u{1f559}',fitzpatrick_scale:!1,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:'\u{1f55a}',fitzpatrick_scale:!1,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:'\u{1f55b}',fitzpatrick_scale:!1,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:'\u{1f55c}',fitzpatrick_scale:!1,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:'\u{1f55d}',fitzpatrick_scale:!1,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:'\u{1f55e}',fitzpatrick_scale:!1,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:'\u{1f55f}',fitzpatrick_scale:!1,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:'\u{1f560}',fitzpatrick_scale:!1,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:'\u{1f561}',fitzpatrick_scale:!1,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:'\u{1f562}',fitzpatrick_scale:!1,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:'\u{1f563}',fitzpatrick_scale:!1,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:'\u{1f564}',fitzpatrick_scale:!1,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:'\u{1f565}',fitzpatrick_scale:!1,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:'\u{1f566}',fitzpatrick_scale:!1,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:'\u{1f567}',fitzpatrick_scale:!1,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},aland_islands:{keywords:["\xc5land","islands","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:'\u{1f1e8}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},curacao:{keywords:["cura\xe7ao","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:'\u{1f1ea}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:'\u{1f1eb}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:'\u{1f1e9}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:'\u{1f1ef}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:'\u{1f1ef}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:'\u{1f1ef}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:'\u{1f1ef}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:'\u{1f1fd}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:'\u{1f1fe}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:'\u{1f1f0}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:'\u{1f1f4}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:'\u{1f1f6}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},reunion:{keywords:["r\xe9union","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},st_barthelemy:{keywords:["saint","barth\xe9lemy","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:'\u{1f1fc}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:'\u{1f1ff}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:'\u{1f1f0}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:'\u{1f1ec}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},england:{keywords:["flag","english"],char:'\u{1f3f4}\u{e0067}\u{e0062}\u{e0065}\u{e006e}\u{e0067}\u{e007f}',fitzpatrick_scale:!1,category:"flags"},scotland:{keywords:["flag","scottish"],char:'\u{1f3f4}\u{e0067}\u{e0062}\u{e0073}\u{e0063}\u{e0074}\u{e007f}',fitzpatrick_scale:!1,category:"flags"},wales:{keywords:["flag","welsh"],char:'\u{1f3f4}\u{e0067}\u{e0062}\u{e0077}\u{e006c}\u{e0073}\u{e007f}',fitzpatrick_scale:!1,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:'\u{1f1fc}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:'\u{1f1fe}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:'\u{1f1ff}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:'\u{1f1ff}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:'\u{1f1fa}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:'\u{1f3f4}\u200d\u2620\ufe0f',fitzpatrick_scale:!1,category:"flags"}}); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.js b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.js new file mode 100644 index 0000000..88455e9 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.js @@ -0,0 +1 @@ +window.tinymce.Resource.add("tinymce.plugins.emoticons",{grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:"😀",fitzpatrick_scale:false,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:"😬",fitzpatrick_scale:false,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:"😁",fitzpatrick_scale:false,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:"😂",fitzpatrick_scale:false,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:"🤣",fitzpatrick_scale:false,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:"🥳",fitzpatrick_scale:false,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:"😃",fitzpatrick_scale:false,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:"😄",fitzpatrick_scale:false,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:"😅",fitzpatrick_scale:false,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:"😆",fitzpatrick_scale:false,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:"😇",fitzpatrick_scale:false,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:"😉",fitzpatrick_scale:false,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:"😊",fitzpatrick_scale:false,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:"🙂",fitzpatrick_scale:false,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:"🙃",fitzpatrick_scale:false,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:"☺️",fitzpatrick_scale:false,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:"😋",fitzpatrick_scale:false,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:"😌",fitzpatrick_scale:false,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:"😍",fitzpatrick_scale:false,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:"🥰",fitzpatrick_scale:false,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"😘",fitzpatrick_scale:false,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:"😗",fitzpatrick_scale:false,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:"😙",fitzpatrick_scale:false,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"😚",fitzpatrick_scale:false,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:"😜",fitzpatrick_scale:false,category:"people"},zany:{keywords:["face","goofy","crazy"],char:"🤪",fitzpatrick_scale:false,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:"🤨",fitzpatrick_scale:false,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:"🧐",fitzpatrick_scale:false,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:"😝",fitzpatrick_scale:false,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:"😛",fitzpatrick_scale:false,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:"🤑",fitzpatrick_scale:false,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:"🤓",fitzpatrick_scale:false,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:"😎",fitzpatrick_scale:false,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:"🤩",fitzpatrick_scale:false,category:"people"},clown_face:{keywords:["face"],char:"🤡",fitzpatrick_scale:false,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:"🤠",fitzpatrick_scale:false,category:"people"},hugs:{keywords:["face","smile","hug"],char:"🤗",fitzpatrick_scale:false,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:"😏",fitzpatrick_scale:false,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:"😶",fitzpatrick_scale:false,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:"😐",fitzpatrick_scale:false,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:"😑",fitzpatrick_scale:false,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:"😒",fitzpatrick_scale:false,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:"🙄",fitzpatrick_scale:false,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:"🤔",fitzpatrick_scale:false,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:"🤥",fitzpatrick_scale:false,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:"🤭",fitzpatrick_scale:false,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:"🤫",fitzpatrick_scale:false,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:"🤬",fitzpatrick_scale:false,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:"🤯",fitzpatrick_scale:false,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:"😳",fitzpatrick_scale:false,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:"😞",fitzpatrick_scale:false,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:"😟",fitzpatrick_scale:false,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:"😠",fitzpatrick_scale:false,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:"😡",fitzpatrick_scale:false,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:"😔",fitzpatrick_scale:false,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:"😕",fitzpatrick_scale:false,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:"🙁",fitzpatrick_scale:false,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:"☹",fitzpatrick_scale:false,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:"😣",fitzpatrick_scale:false,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:"😖",fitzpatrick_scale:false,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:"😫",fitzpatrick_scale:false,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:"😩",fitzpatrick_scale:false,category:"people"},pleading:{keywords:["face","begging","mercy"],char:"🥺",fitzpatrick_scale:false,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:"😤",fitzpatrick_scale:false,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:"😮",fitzpatrick_scale:false,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:"😱",fitzpatrick_scale:false,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:"😨",fitzpatrick_scale:false,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:"😰",fitzpatrick_scale:false,category:"people"},hushed:{keywords:["face","woo","shh"],char:"😯",fitzpatrick_scale:false,category:"people"},frowning:{keywords:["face","aw","what"],char:"😦",fitzpatrick_scale:false,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:"😧",fitzpatrick_scale:false,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:"😢",fitzpatrick_scale:false,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:"😥",fitzpatrick_scale:false,category:"people"},drooling_face:{keywords:["face"],char:"🤤",fitzpatrick_scale:false,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:"😪",fitzpatrick_scale:false,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:"😓",fitzpatrick_scale:false,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:"🥵",fitzpatrick_scale:false,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:"🥶",fitzpatrick_scale:false,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:"😭",fitzpatrick_scale:false,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:"😵",fitzpatrick_scale:false,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:"😲",fitzpatrick_scale:false,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:"🤐",fitzpatrick_scale:false,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:"🤢",fitzpatrick_scale:false,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:"🤧",fitzpatrick_scale:false,category:"people"},vomiting:{keywords:["face","sick"],char:"🤮",fitzpatrick_scale:false,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:"😷",fitzpatrick_scale:false,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:"🤒",fitzpatrick_scale:false,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:"🤕",fitzpatrick_scale:false,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:"🥴",fitzpatrick_scale:false,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:"😴",fitzpatrick_scale:false,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:"💤",fitzpatrick_scale:false,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:"💩",fitzpatrick_scale:false,category:"people"},smiling_imp:{keywords:["devil","horns"],char:"😈",fitzpatrick_scale:false,category:"people"},imp:{keywords:["devil","angry","horns"],char:"👿",fitzpatrick_scale:false,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:"👹",fitzpatrick_scale:false,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:"👺",fitzpatrick_scale:false,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:"💀",fitzpatrick_scale:false,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:"👻",fitzpatrick_scale:false,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:"👽",fitzpatrick_scale:false,category:"people"},robot:{keywords:["computer","machine","bot"],char:"🤖",fitzpatrick_scale:false,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:"😺",fitzpatrick_scale:false,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:"😸",fitzpatrick_scale:false,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:"😹",fitzpatrick_scale:false,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:"😻",fitzpatrick_scale:false,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:"😼",fitzpatrick_scale:false,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:"😽",fitzpatrick_scale:false,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:"🙀",fitzpatrick_scale:false,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:"😿",fitzpatrick_scale:false,category:"people"},pouting_cat:{keywords:["animal","cats"],char:"😾",fitzpatrick_scale:false,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:"🤲",fitzpatrick_scale:true,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:"🙌",fitzpatrick_scale:true,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:"👏",fitzpatrick_scale:true,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:"👋",fitzpatrick_scale:true,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:"🤙",fitzpatrick_scale:true,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:"👍",fitzpatrick_scale:true,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:"👎",fitzpatrick_scale:true,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:"👊",fitzpatrick_scale:true,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:"✊",fitzpatrick_scale:true,category:"people"},fist_left:{keywords:["hand","fistbump"],char:"🤛",fitzpatrick_scale:true,category:"people"},fist_right:{keywords:["hand","fistbump"],char:"🤜",fitzpatrick_scale:true,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:"✌",fitzpatrick_scale:true,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:"👌",fitzpatrick_scale:true,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:"✋",fitzpatrick_scale:true,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:"🤚",fitzpatrick_scale:true,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:"👐",fitzpatrick_scale:true,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:"💪",fitzpatrick_scale:true,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:"🙏",fitzpatrick_scale:true,category:"people"},foot:{keywords:["kick","stomp"],char:"🦶",fitzpatrick_scale:true,category:"people"},leg:{keywords:["kick","limb"],char:"🦵",fitzpatrick_scale:true,category:"people"},handshake:{keywords:["agreement","shake"],char:"🤝",fitzpatrick_scale:false,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:"☝",fitzpatrick_scale:true,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:"👆",fitzpatrick_scale:true,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:"👇",fitzpatrick_scale:true,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:"👈",fitzpatrick_scale:true,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:"👉",fitzpatrick_scale:true,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:"🖕",fitzpatrick_scale:true,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:"🖐",fitzpatrick_scale:true,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:"🤟",fitzpatrick_scale:true,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:"🤘",fitzpatrick_scale:true,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:"🤞",fitzpatrick_scale:true,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:"🖖",fitzpatrick_scale:true,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:"✍",fitzpatrick_scale:true,category:"people"},selfie:{keywords:["camera","phone"],char:"🤳",fitzpatrick_scale:true,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:"💅",fitzpatrick_scale:true,category:"people"},lips:{keywords:["mouth","kiss"],char:"👄",fitzpatrick_scale:false,category:"people"},tooth:{keywords:["teeth","dentist"],char:"🦷",fitzpatrick_scale:false,category:"people"},tongue:{keywords:["mouth","playful"],char:"👅",fitzpatrick_scale:false,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:"👂",fitzpatrick_scale:true,category:"people"},nose:{keywords:["smell","sniff"],char:"👃",fitzpatrick_scale:true,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:"👁",fitzpatrick_scale:false,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:"👀",fitzpatrick_scale:false,category:"people"},brain:{keywords:["smart","intelligent"],char:"🧠",fitzpatrick_scale:false,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:"👤",fitzpatrick_scale:false,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:"👥",fitzpatrick_scale:false,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:"🗣",fitzpatrick_scale:false,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:"👶",fitzpatrick_scale:true,category:"people"},child:{keywords:["gender-neutral","young"],char:"🧒",fitzpatrick_scale:true,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:"👦",fitzpatrick_scale:true,category:"people"},girl:{keywords:["female","woman","teenager"],char:"👧",fitzpatrick_scale:true,category:"people"},adult:{keywords:["gender-neutral","person"],char:"🧑",fitzpatrick_scale:true,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:"👨",fitzpatrick_scale:true,category:"people"},woman:{keywords:["female","girls","lady"],char:"👩",fitzpatrick_scale:true,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:"👱‍♀️",fitzpatrick_scale:true,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:"👱",fitzpatrick_scale:true,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:"🧔",fitzpatrick_scale:true,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:"🧓",fitzpatrick_scale:true,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:"👴",fitzpatrick_scale:true,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:"👵",fitzpatrick_scale:true,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:"👲",fitzpatrick_scale:true,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:"🧕",fitzpatrick_scale:true,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:"👳‍♀️",fitzpatrick_scale:true,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:"👳",fitzpatrick_scale:true,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:"👮‍♀️",fitzpatrick_scale:true,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:"👮",fitzpatrick_scale:true,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:"👷‍♀️",fitzpatrick_scale:true,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:"👷",fitzpatrick_scale:true,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:"💂‍♀️",fitzpatrick_scale:true,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:"💂",fitzpatrick_scale:true,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:"🕵️‍♀️",fitzpatrick_scale:true,category:"people"},male_detective:{keywords:["human","spy","detective"],char:"🕵",fitzpatrick_scale:true,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:"👩‍⚕️",fitzpatrick_scale:true,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:"👨‍⚕️",fitzpatrick_scale:true,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:"👩‍🌾",fitzpatrick_scale:true,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:"👨‍🌾",fitzpatrick_scale:true,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:"👩‍🍳",fitzpatrick_scale:true,category:"people"},man_cook:{keywords:["chef","man","human"],char:"👨‍🍳",fitzpatrick_scale:true,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:"👩‍🎓",fitzpatrick_scale:true,category:"people"},man_student:{keywords:["graduate","man","human"],char:"👨‍🎓",fitzpatrick_scale:true,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:"👩‍🎤",fitzpatrick_scale:true,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:"👨‍🎤",fitzpatrick_scale:true,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:"👩‍🏫",fitzpatrick_scale:true,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:"👨‍🏫",fitzpatrick_scale:true,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:"👩‍🏭",fitzpatrick_scale:true,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:"👨‍🏭",fitzpatrick_scale:true,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:"👩‍💻",fitzpatrick_scale:true,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:"👨‍💻",fitzpatrick_scale:true,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:"👩‍💼",fitzpatrick_scale:true,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:"👨‍💼",fitzpatrick_scale:true,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:"👩‍🔧",fitzpatrick_scale:true,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:"👨‍🔧",fitzpatrick_scale:true,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:"👩‍🔬",fitzpatrick_scale:true,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:"👨‍🔬",fitzpatrick_scale:true,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:"👩‍🎨",fitzpatrick_scale:true,category:"people"},man_artist:{keywords:["painter","man","human"],char:"👨‍🎨",fitzpatrick_scale:true,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:"👩‍🚒",fitzpatrick_scale:true,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:"👨‍🚒",fitzpatrick_scale:true,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:"👩‍✈️",fitzpatrick_scale:true,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:"👨‍✈️",fitzpatrick_scale:true,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:"👩‍🚀",fitzpatrick_scale:true,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:"👨‍🚀",fitzpatrick_scale:true,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:"👩‍⚖️",fitzpatrick_scale:true,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:"👨‍⚖️",fitzpatrick_scale:true,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:"🦸‍♀️",fitzpatrick_scale:true,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:"🦸‍♂️",fitzpatrick_scale:true,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:"🦹‍♀️",fitzpatrick_scale:true,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:"🦹‍♂️",fitzpatrick_scale:true,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:"🤶",fitzpatrick_scale:true,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:"🎅",fitzpatrick_scale:true,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:"🧙‍♀️",fitzpatrick_scale:true,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:"🧙‍♂️",fitzpatrick_scale:true,category:"people"},woman_elf:{keywords:["woman","female"],char:"🧝‍♀️",fitzpatrick_scale:true,category:"people"},man_elf:{keywords:["man","male"],char:"🧝‍♂️",fitzpatrick_scale:true,category:"people"},woman_vampire:{keywords:["woman","female"],char:"🧛‍♀️",fitzpatrick_scale:true,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:"🧛‍♂️",fitzpatrick_scale:true,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:"🧟‍♀️",fitzpatrick_scale:false,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:"🧟‍♂️",fitzpatrick_scale:false,category:"people"},woman_genie:{keywords:["woman","female"],char:"🧞‍♀️",fitzpatrick_scale:false,category:"people"},man_genie:{keywords:["man","male"],char:"🧞‍♂️",fitzpatrick_scale:false,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:"🧜‍♀️",fitzpatrick_scale:true,category:"people"},merman:{keywords:["man","male","triton"],char:"🧜‍♂️",fitzpatrick_scale:true,category:"people"},woman_fairy:{keywords:["woman","female"],char:"🧚‍♀️",fitzpatrick_scale:true,category:"people"},man_fairy:{keywords:["man","male"],char:"🧚‍♂️",fitzpatrick_scale:true,category:"people"},angel:{keywords:["heaven","wings","halo"],char:"👼",fitzpatrick_scale:true,category:"people"},pregnant_woman:{keywords:["baby"],char:"🤰",fitzpatrick_scale:true,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:"🤱",fitzpatrick_scale:true,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:"👸",fitzpatrick_scale:true,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:"🤴",fitzpatrick_scale:true,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:"👰",fitzpatrick_scale:true,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:"🤵",fitzpatrick_scale:true,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:"🏃‍♀️",fitzpatrick_scale:true,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:"🏃",fitzpatrick_scale:true,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:"🚶‍♀️",fitzpatrick_scale:true,category:"people"},walking_man:{keywords:["human","feet","steps"],char:"🚶",fitzpatrick_scale:true,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:"💃",fitzpatrick_scale:true,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:"🕺",fitzpatrick_scale:true,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:"👯",fitzpatrick_scale:false,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:"👯‍♂️",fitzpatrick_scale:false,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:"👫",fitzpatrick_scale:false,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:"👬",fitzpatrick_scale:false,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:"👭",fitzpatrick_scale:false,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:"🙇‍♀️",fitzpatrick_scale:true,category:"people"},bowing_man:{keywords:["man","male","boy"],char:"🙇",fitzpatrick_scale:true,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:"🤦‍♂️",fitzpatrick_scale:true,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:"🤦‍♀️",fitzpatrick_scale:true,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:"🤷",fitzpatrick_scale:true,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:"🤷‍♂️",fitzpatrick_scale:true,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:"💁",fitzpatrick_scale:true,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:"💁‍♂️",fitzpatrick_scale:true,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:"🙅",fitzpatrick_scale:true,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:"🙅‍♂️",fitzpatrick_scale:true,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:"🙆",fitzpatrick_scale:true,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:"🙆‍♂️",fitzpatrick_scale:true,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:"🙋",fitzpatrick_scale:true,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:"🙋‍♂️",fitzpatrick_scale:true,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:"🙎",fitzpatrick_scale:true,category:"people"},pouting_man:{keywords:["male","boy","man"],char:"🙎‍♂️",fitzpatrick_scale:true,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:"🙍",fitzpatrick_scale:true,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:"🙍‍♂️",fitzpatrick_scale:true,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:"💇",fitzpatrick_scale:true,category:"people"},haircut_man:{keywords:["male","boy","man"],char:"💇‍♂️",fitzpatrick_scale:true,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:"💆",fitzpatrick_scale:true,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:"💆‍♂️",fitzpatrick_scale:true,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:"🧖‍♀️",fitzpatrick_scale:true,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:"🧖‍♂️",fitzpatrick_scale:true,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"💑",fitzpatrick_scale:false,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"👩‍❤️‍👩",fitzpatrick_scale:false,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"👨‍❤️‍👨",fitzpatrick_scale:false,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"💏",fitzpatrick_scale:false,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"👩‍❤️‍💋‍👩",fitzpatrick_scale:false,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:"👨‍❤️‍💋‍👨",fitzpatrick_scale:false,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:"👪",fitzpatrick_scale:false,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:"👨‍👩‍👧",fitzpatrick_scale:false,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👩‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👩‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"👨‍👩‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👦",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👧",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👦",fitzpatrick_scale:false,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👧",fitzpatrick_scale:false,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:"👩‍👦",fitzpatrick_scale:false,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:"👩‍👧",fitzpatrick_scale:false,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:"👩‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:"👩‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:"👩‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:"👨‍👦",fitzpatrick_scale:false,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:"👨‍👧",fitzpatrick_scale:false,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:"👨‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:"👨‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:"👨‍👧‍👧",fitzpatrick_scale:false,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:"🧶",fitzpatrick_scale:false,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:"🧵",fitzpatrick_scale:false,category:"people"},coat:{keywords:["jacket"],char:"🧥",fitzpatrick_scale:false,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:"🥼",fitzpatrick_scale:false,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:"👚",fitzpatrick_scale:false,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:"👕",fitzpatrick_scale:false,category:"people"},jeans:{keywords:["fashion","shopping"],char:"👖",fitzpatrick_scale:false,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:"👔",fitzpatrick_scale:false,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:"👗",fitzpatrick_scale:false,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:"👙",fitzpatrick_scale:false,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:"👘",fitzpatrick_scale:false,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:"💄",fitzpatrick_scale:false,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:"💋",fitzpatrick_scale:false,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:"👣",fitzpatrick_scale:false,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:"🥿",fitzpatrick_scale:false,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:"👠",fitzpatrick_scale:false,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:"👡",fitzpatrick_scale:false,category:"people"},boot:{keywords:["shoes","fashion"],char:"👢",fitzpatrick_scale:false,category:"people"},mans_shoe:{keywords:["fashion","male"],char:"👞",fitzpatrick_scale:false,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:"👟",fitzpatrick_scale:false,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:"🥾",fitzpatrick_scale:false,category:"people"},socks:{keywords:["stockings","clothes"],char:"🧦",fitzpatrick_scale:false,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:"🧤",fitzpatrick_scale:false,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:"🧣",fitzpatrick_scale:false,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:"👒",fitzpatrick_scale:false,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:"🎩",fitzpatrick_scale:false,category:"people"},billed_hat:{keywords:["cap","baseball"],char:"🧢",fitzpatrick_scale:false,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:"⛑",fitzpatrick_scale:false,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:"🎓",fitzpatrick_scale:false,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:"👑",fitzpatrick_scale:false,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:"🎒",fitzpatrick_scale:false,category:"people"},luggage:{keywords:["packing","travel"],char:"🧳",fitzpatrick_scale:false,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:"👝",fitzpatrick_scale:false,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:"👛",fitzpatrick_scale:false,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:"👜",fitzpatrick_scale:false,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:"💼",fitzpatrick_scale:false,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:"👓",fitzpatrick_scale:false,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:"🕶",fitzpatrick_scale:false,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:"🥽",fitzpatrick_scale:false,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:"💍",fitzpatrick_scale:false,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:"🌂",fitzpatrick_scale:false,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:"🐶",fitzpatrick_scale:false,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:"🐱",fitzpatrick_scale:false,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:"🐭",fitzpatrick_scale:false,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:"🐹",fitzpatrick_scale:false,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:"🐰",fitzpatrick_scale:false,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:"🦊",fitzpatrick_scale:false,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:"🐻",fitzpatrick_scale:false,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:"🐼",fitzpatrick_scale:false,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:"🐨",fitzpatrick_scale:false,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:"🐯",fitzpatrick_scale:false,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:"🦁",fitzpatrick_scale:false,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:"🐮",fitzpatrick_scale:false,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:"🐷",fitzpatrick_scale:false,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:"🐽",fitzpatrick_scale:false,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:"🐸",fitzpatrick_scale:false,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:"🦑",fitzpatrick_scale:false,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:"🐙",fitzpatrick_scale:false,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:"🦐",fitzpatrick_scale:false,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:"🐵",fitzpatrick_scale:false,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:"🦍",fitzpatrick_scale:false,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:"🙈",fitzpatrick_scale:false,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:"🙉",fitzpatrick_scale:false,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:"🙊",fitzpatrick_scale:false,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:"🐒",fitzpatrick_scale:false,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:"🐔",fitzpatrick_scale:false,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:"🐧",fitzpatrick_scale:false,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:"🐦",fitzpatrick_scale:false,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:"🐤",fitzpatrick_scale:false,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:"🐣",fitzpatrick_scale:false,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:"🐥",fitzpatrick_scale:false,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:"🦆",fitzpatrick_scale:false,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:"🦅",fitzpatrick_scale:false,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:"🦉",fitzpatrick_scale:false,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:"🦇",fitzpatrick_scale:false,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:"🐺",fitzpatrick_scale:false,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:"🐗",fitzpatrick_scale:false,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:"🐴",fitzpatrick_scale:false,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:"🦄",fitzpatrick_scale:false,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:"🐝",fitzpatrick_scale:false,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:"🐛",fitzpatrick_scale:false,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:"🦋",fitzpatrick_scale:false,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:"🐌",fitzpatrick_scale:false,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:"🐞",fitzpatrick_scale:false,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:"🐜",fitzpatrick_scale:false,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:"🦗",fitzpatrick_scale:false,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:"🕷",fitzpatrick_scale:false,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:"🦂",fitzpatrick_scale:false,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:"🦀",fitzpatrick_scale:false,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:"🐍",fitzpatrick_scale:false,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:"🦎",fitzpatrick_scale:false,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:"🦖",fitzpatrick_scale:false,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:"🦕",fitzpatrick_scale:false,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:"🐢",fitzpatrick_scale:false,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:"🐠",fitzpatrick_scale:false,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:"🐟",fitzpatrick_scale:false,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:"🐡",fitzpatrick_scale:false,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:"🐬",fitzpatrick_scale:false,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:"🦈",fitzpatrick_scale:false,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:"🐳",fitzpatrick_scale:false,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:"🐋",fitzpatrick_scale:false,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:"🐊",fitzpatrick_scale:false,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:"🐆",fitzpatrick_scale:false,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:"🦓",fitzpatrick_scale:false,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:"🐅",fitzpatrick_scale:false,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:"🐃",fitzpatrick_scale:false,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:"🐂",fitzpatrick_scale:false,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:"🐄",fitzpatrick_scale:false,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:"🦌",fitzpatrick_scale:false,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:"🐪",fitzpatrick_scale:false,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:"🐫",fitzpatrick_scale:false,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:"🦒",fitzpatrick_scale:false,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:"🐘",fitzpatrick_scale:false,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:"🦏",fitzpatrick_scale:false,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:"🐐",fitzpatrick_scale:false,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:"🐏",fitzpatrick_scale:false,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:"🐑",fitzpatrick_scale:false,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:"🐎",fitzpatrick_scale:false,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:"🐖",fitzpatrick_scale:false,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:"🐀",fitzpatrick_scale:false,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:"🐁",fitzpatrick_scale:false,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:"🐓",fitzpatrick_scale:false,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:"🦃",fitzpatrick_scale:false,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:"🕊",fitzpatrick_scale:false,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:"🐕",fitzpatrick_scale:false,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:"🐩",fitzpatrick_scale:false,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:"🐈",fitzpatrick_scale:false,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:"🐇",fitzpatrick_scale:false,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:"🐿",fitzpatrick_scale:false,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:"🦔",fitzpatrick_scale:false,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:"🦝",fitzpatrick_scale:false,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:"🦙",fitzpatrick_scale:false,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:"🦛",fitzpatrick_scale:false,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:"🦘",fitzpatrick_scale:false,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:"🦡",fitzpatrick_scale:false,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:"🦢",fitzpatrick_scale:false,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:"🦚",fitzpatrick_scale:false,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:"🦜",fitzpatrick_scale:false,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:"🦞",fitzpatrick_scale:false,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:"🦟",fitzpatrick_scale:false,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:"🐾",fitzpatrick_scale:false,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:"🐉",fitzpatrick_scale:false,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:"🐲",fitzpatrick_scale:false,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:"🌵",fitzpatrick_scale:false,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:"🎄",fitzpatrick_scale:false,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:"🌲",fitzpatrick_scale:false,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:"🌳",fitzpatrick_scale:false,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:"🌴",fitzpatrick_scale:false,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:"🌱",fitzpatrick_scale:false,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:"🌿",fitzpatrick_scale:false,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:"☘",fitzpatrick_scale:false,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:"🍀",fitzpatrick_scale:false,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:"🎍",fitzpatrick_scale:false,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:"🎋",fitzpatrick_scale:false,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:"🍃",fitzpatrick_scale:false,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:"🍂",fitzpatrick_scale:false,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:"🍁",fitzpatrick_scale:false,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:"🌾",fitzpatrick_scale:false,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:"🌺",fitzpatrick_scale:false,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:"🌻",fitzpatrick_scale:false,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:"🌹",fitzpatrick_scale:false,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:"🥀",fitzpatrick_scale:false,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:"🌷",fitzpatrick_scale:false,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:"🌼",fitzpatrick_scale:false,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:"🌸",fitzpatrick_scale:false,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:"💐",fitzpatrick_scale:false,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:"🍄",fitzpatrick_scale:false,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:"🌰",fitzpatrick_scale:false,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:"🎃",fitzpatrick_scale:false,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:"🐚",fitzpatrick_scale:false,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:"🕸",fitzpatrick_scale:false,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:"🌎",fitzpatrick_scale:false,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:"🌍",fitzpatrick_scale:false,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:"🌏",fitzpatrick_scale:false,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:"🌕",fitzpatrick_scale:false,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:"🌖",fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌗",fitzpatrick_scale:false,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌘",fitzpatrick_scale:false,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌑",fitzpatrick_scale:false,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌒",fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌓",fitzpatrick_scale:false,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:"🌔",fitzpatrick_scale:false,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌚",fitzpatrick_scale:false,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌝",fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌛",fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌜",fitzpatrick_scale:false,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:"🌞",fitzpatrick_scale:false,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:"🌙",fitzpatrick_scale:false,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:"⭐",fitzpatrick_scale:false,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:"🌟",fitzpatrick_scale:false,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:"💫",fitzpatrick_scale:false,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:"✨",fitzpatrick_scale:false,category:"animals_and_nature"},comet:{keywords:["space"],char:"☄",fitzpatrick_scale:false,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:"☀️",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:"🌤",fitzpatrick_scale:false,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:"⛅",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:"🌥",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:"🌦",fitzpatrick_scale:false,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:"☁️",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:"🌧",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:"⛈",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:"🌩",fitzpatrick_scale:false,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:"⚡",fitzpatrick_scale:false,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:"🔥",fitzpatrick_scale:false,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:"💥",fitzpatrick_scale:false,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:"❄️",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:"🌨",fitzpatrick_scale:false,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:"⛄",fitzpatrick_scale:false,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:"☃",fitzpatrick_scale:false,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:"🌬",fitzpatrick_scale:false,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:"💨",fitzpatrick_scale:false,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:"🌪",fitzpatrick_scale:false,category:"animals_and_nature"},fog:{keywords:["weather"],char:"🌫",fitzpatrick_scale:false,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:"☂",fitzpatrick_scale:false,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:"☔",fitzpatrick_scale:false,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:"💧",fitzpatrick_scale:false,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:"💦",fitzpatrick_scale:false,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:"🌊",fitzpatrick_scale:false,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:"🍏",fitzpatrick_scale:false,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:"🍎",fitzpatrick_scale:false,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:"🍐",fitzpatrick_scale:false,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:"🍊",fitzpatrick_scale:false,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:"🍋",fitzpatrick_scale:false,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:"🍌",fitzpatrick_scale:false,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:"🍉",fitzpatrick_scale:false,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:"🍇",fitzpatrick_scale:false,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:"🍓",fitzpatrick_scale:false,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:"🍈",fitzpatrick_scale:false,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:"🍒",fitzpatrick_scale:false,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:"🍑",fitzpatrick_scale:false,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:"🍍",fitzpatrick_scale:false,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:"🥥",fitzpatrick_scale:false,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:"🥝",fitzpatrick_scale:false,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:"🥭",fitzpatrick_scale:false,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:"🥑",fitzpatrick_scale:false,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:"🥦",fitzpatrick_scale:false,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:"🍅",fitzpatrick_scale:false,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:"🍆",fitzpatrick_scale:false,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:"🥒",fitzpatrick_scale:false,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:"🥕",fitzpatrick_scale:false,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:"🌶",fitzpatrick_scale:false,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:"🥔",fitzpatrick_scale:false,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:"🌽",fitzpatrick_scale:false,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:"🥬",fitzpatrick_scale:false,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:"🍠",fitzpatrick_scale:false,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:"🥜",fitzpatrick_scale:false,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:"🍯",fitzpatrick_scale:false,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:"🥐",fitzpatrick_scale:false,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:"🍞",fitzpatrick_scale:false,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:"🥖",fitzpatrick_scale:false,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:"🥯",fitzpatrick_scale:false,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:"🥨",fitzpatrick_scale:false,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:"🧀",fitzpatrick_scale:false,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:"🥚",fitzpatrick_scale:false,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:"🥓",fitzpatrick_scale:false,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:"🥩",fitzpatrick_scale:false,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:"🥞",fitzpatrick_scale:false,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:"🍗",fitzpatrick_scale:false,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:"🍖",fitzpatrick_scale:false,category:"food_and_drink"},bone:{keywords:["skeleton"],char:"🦴",fitzpatrick_scale:false,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:"🍤",fitzpatrick_scale:false,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:"🍳",fitzpatrick_scale:false,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:"🍔",fitzpatrick_scale:false,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:"🍟",fitzpatrick_scale:false,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:"🥙",fitzpatrick_scale:false,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:"🌭",fitzpatrick_scale:false,category:"food_and_drink"},pizza:{keywords:["food","party"],char:"🍕",fitzpatrick_scale:false,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:"🥪",fitzpatrick_scale:false,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:"🥫",fitzpatrick_scale:false,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:"🍝",fitzpatrick_scale:false,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:"🌮",fitzpatrick_scale:false,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:"🌯",fitzpatrick_scale:false,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:"🥗",fitzpatrick_scale:false,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:"🥘",fitzpatrick_scale:false,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:"🍜",fitzpatrick_scale:false,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:"🍲",fitzpatrick_scale:false,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:"🍥",fitzpatrick_scale:false,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:"🥠",fitzpatrick_scale:false,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:"🍣",fitzpatrick_scale:false,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:"🍱",fitzpatrick_scale:false,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:"🍛",fitzpatrick_scale:false,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:"🍙",fitzpatrick_scale:false,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:"🍚",fitzpatrick_scale:false,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:"🍘",fitzpatrick_scale:false,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:"🍢",fitzpatrick_scale:false,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:"🍡",fitzpatrick_scale:false,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:"🍧",fitzpatrick_scale:false,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:"🍨",fitzpatrick_scale:false,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:"🍦",fitzpatrick_scale:false,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:"🥧",fitzpatrick_scale:false,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:"🍰",fitzpatrick_scale:false,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:"🧁",fitzpatrick_scale:false,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:"🥮",fitzpatrick_scale:false,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:"🎂",fitzpatrick_scale:false,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:"🍮",fitzpatrick_scale:false,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:"🍬",fitzpatrick_scale:false,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:"🍭",fitzpatrick_scale:false,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:"🍫",fitzpatrick_scale:false,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:"🍿",fitzpatrick_scale:false,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:"🥟",fitzpatrick_scale:false,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:"🍩",fitzpatrick_scale:false,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:"🍪",fitzpatrick_scale:false,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:"🥛",fitzpatrick_scale:false,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"🍺",fitzpatrick_scale:false,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"🍻",fitzpatrick_scale:false,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:"🥂",fitzpatrick_scale:false,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:"🍷",fitzpatrick_scale:false,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:"🥃",fitzpatrick_scale:false,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:"🍸",fitzpatrick_scale:false,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:"🍹",fitzpatrick_scale:false,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:"🍾",fitzpatrick_scale:false,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:"🍶",fitzpatrick_scale:false,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:"🍵",fitzpatrick_scale:false,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:"🥤",fitzpatrick_scale:false,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:"☕",fitzpatrick_scale:false,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:"🍼",fitzpatrick_scale:false,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:"🧂",fitzpatrick_scale:false,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:"🥄",fitzpatrick_scale:false,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:"🍴",fitzpatrick_scale:false,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:"🍽",fitzpatrick_scale:false,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:"🥣",fitzpatrick_scale:false,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:"🥡",fitzpatrick_scale:false,category:"food_and_drink"},chopsticks:{keywords:["food"],char:"🥢",fitzpatrick_scale:false,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:"⚽",fitzpatrick_scale:false,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:"🏀",fitzpatrick_scale:false,category:"activity"},football:{keywords:["sports","balls","NFL"],char:"🏈",fitzpatrick_scale:false,category:"activity"},baseball:{keywords:["sports","balls"],char:"⚾",fitzpatrick_scale:false,category:"activity"},softball:{keywords:["sports","balls"],char:"🥎",fitzpatrick_scale:false,category:"activity"},tennis:{keywords:["sports","balls","green"],char:"🎾",fitzpatrick_scale:false,category:"activity"},volleyball:{keywords:["sports","balls"],char:"🏐",fitzpatrick_scale:false,category:"activity"},rugby_football:{keywords:["sports","team"],char:"🏉",fitzpatrick_scale:false,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:"🥏",fitzpatrick_scale:false,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:"🎱",fitzpatrick_scale:false,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:"⛳",fitzpatrick_scale:false,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:"🏌️‍♀️",fitzpatrick_scale:false,category:"activity"},golfing_man:{keywords:["sports","business"],char:"🏌",fitzpatrick_scale:true,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:"🏓",fitzpatrick_scale:false,category:"activity"},badminton:{keywords:["sports"],char:"🏸",fitzpatrick_scale:false,category:"activity"},goal_net:{keywords:["sports"],char:"🥅",fitzpatrick_scale:false,category:"activity"},ice_hockey:{keywords:["sports"],char:"🏒",fitzpatrick_scale:false,category:"activity"},field_hockey:{keywords:["sports"],char:"🏑",fitzpatrick_scale:false,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:"🥍",fitzpatrick_scale:false,category:"activity"},cricket:{keywords:["sports"],char:"🏏",fitzpatrick_scale:false,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:"🎿",fitzpatrick_scale:false,category:"activity"},skier:{keywords:["sports","winter","snow"],char:"⛷",fitzpatrick_scale:false,category:"activity"},snowboarder:{keywords:["sports","winter"],char:"🏂",fitzpatrick_scale:true,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:"🤺",fitzpatrick_scale:false,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:"🤼‍♀️",fitzpatrick_scale:false,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:"🤼‍♂️",fitzpatrick_scale:false,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:"🤸‍♀️",fitzpatrick_scale:true,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:"🤸‍♂️",fitzpatrick_scale:true,category:"activity"},woman_playing_handball:{keywords:["sports"],char:"🤾‍♀️",fitzpatrick_scale:true,category:"activity"},man_playing_handball:{keywords:["sports"],char:"🤾‍♂️",fitzpatrick_scale:true,category:"activity"},ice_skate:{keywords:["sports"],char:"⛸",fitzpatrick_scale:false,category:"activity"},curling_stone:{keywords:["sports"],char:"🥌",fitzpatrick_scale:false,category:"activity"},skateboard:{keywords:["board"],char:"🛹",fitzpatrick_scale:false,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:"🛷",fitzpatrick_scale:false,category:"activity"},bow_and_arrow:{keywords:["sports"],char:"🏹",fitzpatrick_scale:false,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:"🎣",fitzpatrick_scale:false,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:"🥊",fitzpatrick_scale:false,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:"🥋",fitzpatrick_scale:false,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:"🚣‍♀️",fitzpatrick_scale:true,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:"🚣",fitzpatrick_scale:true,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:"🧗‍♀️",fitzpatrick_scale:true,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:"🧗‍♂️",fitzpatrick_scale:true,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:"🏊‍♀️",fitzpatrick_scale:true,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:"🏊",fitzpatrick_scale:true,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:"🤽‍♀️",fitzpatrick_scale:true,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:"🤽‍♂️",fitzpatrick_scale:true,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:"🧘‍♀️",fitzpatrick_scale:true,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:"🧘‍♂️",fitzpatrick_scale:true,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:"🏄‍♀️",fitzpatrick_scale:true,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:"🏄",fitzpatrick_scale:true,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:"🛀",fitzpatrick_scale:true,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:"⛹️‍♀️",fitzpatrick_scale:true,category:"activity"},basketball_man:{keywords:["sports","human"],char:"⛹",fitzpatrick_scale:true,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:"🏋️‍♀️",fitzpatrick_scale:true,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:"🏋",fitzpatrick_scale:true,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:"🚴‍♀️",fitzpatrick_scale:true,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:"🚴",fitzpatrick_scale:true,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:"🚵‍♀️",fitzpatrick_scale:true,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:"🚵",fitzpatrick_scale:true,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:"🏇",fitzpatrick_scale:true,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:"🕴",fitzpatrick_scale:true,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:"🏆",fitzpatrick_scale:false,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:"🎽",fitzpatrick_scale:false,category:"activity"},medal_sports:{keywords:["award","winning"],char:"🏅",fitzpatrick_scale:false,category:"activity"},medal_military:{keywords:["award","winning","army"],char:"🎖",fitzpatrick_scale:false,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:"🥇",fitzpatrick_scale:false,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:"🥈",fitzpatrick_scale:false,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:"🥉",fitzpatrick_scale:false,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:"🎗",fitzpatrick_scale:false,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:"🏵",fitzpatrick_scale:false,category:"activity"},ticket:{keywords:["event","concert","pass"],char:"🎫",fitzpatrick_scale:false,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:"🎟",fitzpatrick_scale:false,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:"🎭",fitzpatrick_scale:false,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:"🎨",fitzpatrick_scale:false,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:"🎪",fitzpatrick_scale:false,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:"🤹‍♀️",fitzpatrick_scale:true,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:"🤹‍♂️",fitzpatrick_scale:true,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:"🎤",fitzpatrick_scale:false,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:"🎧",fitzpatrick_scale:false,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:"🎼",fitzpatrick_scale:false,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:"🎹",fitzpatrick_scale:false,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:"🥁",fitzpatrick_scale:false,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:"🎷",fitzpatrick_scale:false,category:"activity"},trumpet:{keywords:["music","brass"],char:"🎺",fitzpatrick_scale:false,category:"activity"},guitar:{keywords:["music","instrument"],char:"🎸",fitzpatrick_scale:false,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:"🎻",fitzpatrick_scale:false,category:"activity"},clapper:{keywords:["movie","film","record"],char:"🎬",fitzpatrick_scale:false,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:"🎮",fitzpatrick_scale:false,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:"👾",fitzpatrick_scale:false,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:"🎯",fitzpatrick_scale:false,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:"🎲",fitzpatrick_scale:false,category:"activity"},chess_pawn:{keywords:["expendable"],char:"♟",fitzpatrick_scale:false,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:"🎰",fitzpatrick_scale:false,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:"🧩",fitzpatrick_scale:false,category:"activity"},bowling:{keywords:["sports","fun","play"],char:"🎳",fitzpatrick_scale:false,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:"🚗",fitzpatrick_scale:false,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:"🚕",fitzpatrick_scale:false,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:"🚙",fitzpatrick_scale:false,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:"🚌",fitzpatrick_scale:false,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:"🚎",fitzpatrick_scale:false,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:"🏎",fitzpatrick_scale:false,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:"🚓",fitzpatrick_scale:false,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:"🚑",fitzpatrick_scale:false,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:"🚒",fitzpatrick_scale:false,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:"🚐",fitzpatrick_scale:false,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:"🚚",fitzpatrick_scale:false,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:"🚛",fitzpatrick_scale:false,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:"🚜",fitzpatrick_scale:false,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:"🛴",fitzpatrick_scale:false,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:"🏍",fitzpatrick_scale:false,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:"🚲",fitzpatrick_scale:false,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:"🛵",fitzpatrick_scale:false,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:"🚨",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:"🚔",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:"🚍",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:"🚘",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:"🚖",fitzpatrick_scale:false,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:"🚡",fitzpatrick_scale:false,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:"🚠",fitzpatrick_scale:false,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:"🚟",fitzpatrick_scale:false,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:"🚃",fitzpatrick_scale:false,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:"🚋",fitzpatrick_scale:false,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:"🚝",fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:"🚄",fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:"🚅",fitzpatrick_scale:false,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:"🚈",fitzpatrick_scale:false,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:"🚞",fitzpatrick_scale:false,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:"🚂",fitzpatrick_scale:false,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:"🚆",fitzpatrick_scale:false,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:"🚇",fitzpatrick_scale:false,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:"🚊",fitzpatrick_scale:false,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:"🚉",fitzpatrick_scale:false,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:"🛸",fitzpatrick_scale:false,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:"🚁",fitzpatrick_scale:false,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:"🛩",fitzpatrick_scale:false,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:"✈️",fitzpatrick_scale:false,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:"🛫",fitzpatrick_scale:false,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:"🛬",fitzpatrick_scale:false,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:"⛵",fitzpatrick_scale:false,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:"🛥",fitzpatrick_scale:false,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:"🚤",fitzpatrick_scale:false,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:"⛴",fitzpatrick_scale:false,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:"🛳",fitzpatrick_scale:false,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:"🚀",fitzpatrick_scale:false,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:"🛰",fitzpatrick_scale:false,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:"💺",fitzpatrick_scale:false,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:"🛶",fitzpatrick_scale:false,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:"⚓",fitzpatrick_scale:false,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:"🚧",fitzpatrick_scale:false,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:"⛽",fitzpatrick_scale:false,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:"🚏",fitzpatrick_scale:false,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:"🚦",fitzpatrick_scale:false,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:"🚥",fitzpatrick_scale:false,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:"🏁",fitzpatrick_scale:false,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:"🚢",fitzpatrick_scale:false,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:"🎡",fitzpatrick_scale:false,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:"🎢",fitzpatrick_scale:false,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:"🎠",fitzpatrick_scale:false,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:"🏗",fitzpatrick_scale:false,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:"🌁",fitzpatrick_scale:false,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:"🗼",fitzpatrick_scale:false,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:"🏭",fitzpatrick_scale:false,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:"⛲",fitzpatrick_scale:false,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:"🎑",fitzpatrick_scale:false,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:"⛰",fitzpatrick_scale:false,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:"🏔",fitzpatrick_scale:false,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:"🗻",fitzpatrick_scale:false,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:"🌋",fitzpatrick_scale:false,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:"🗾",fitzpatrick_scale:false,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:"🏕",fitzpatrick_scale:false,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:"⛺",fitzpatrick_scale:false,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:"🏞",fitzpatrick_scale:false,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:"🛣",fitzpatrick_scale:false,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:"🛤",fitzpatrick_scale:false,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:"🌅",fitzpatrick_scale:false,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:"🌄",fitzpatrick_scale:false,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:"🏜",fitzpatrick_scale:false,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:"🏖",fitzpatrick_scale:false,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:"🏝",fitzpatrick_scale:false,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:"🌇",fitzpatrick_scale:false,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:"🌆",fitzpatrick_scale:false,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:"🏙",fitzpatrick_scale:false,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:"🌃",fitzpatrick_scale:false,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:"🌉",fitzpatrick_scale:false,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:"🌌",fitzpatrick_scale:false,category:"travel_and_places"},stars:{keywords:["night","photo"],char:"🌠",fitzpatrick_scale:false,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:"🎇",fitzpatrick_scale:false,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:"🎆",fitzpatrick_scale:false,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:"🌈",fitzpatrick_scale:false,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:"🏘",fitzpatrick_scale:false,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:"🏰",fitzpatrick_scale:false,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:"🏯",fitzpatrick_scale:false,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:"🏟",fitzpatrick_scale:false,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:"🗽",fitzpatrick_scale:false,category:"travel_and_places"},house:{keywords:["building","home"],char:"🏠",fitzpatrick_scale:false,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:"🏡",fitzpatrick_scale:false,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:"🏚",fitzpatrick_scale:false,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:"🏢",fitzpatrick_scale:false,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:"🏬",fitzpatrick_scale:false,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:"🏣",fitzpatrick_scale:false,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:"🏤",fitzpatrick_scale:false,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:"🏥",fitzpatrick_scale:false,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:"🏦",fitzpatrick_scale:false,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:"🏨",fitzpatrick_scale:false,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:"🏪",fitzpatrick_scale:false,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:"🏫",fitzpatrick_scale:false,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:"🏩",fitzpatrick_scale:false,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:"💒",fitzpatrick_scale:false,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:"🏛",fitzpatrick_scale:false,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:"⛪",fitzpatrick_scale:false,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:"🕌",fitzpatrick_scale:false,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:"🕍",fitzpatrick_scale:false,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:"🕋",fitzpatrick_scale:false,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:"⛩",fitzpatrick_scale:false,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:"⌚",fitzpatrick_scale:false,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:"📱",fitzpatrick_scale:false,category:"objects"},calling:{keywords:["iphone","incoming"],char:"📲",fitzpatrick_scale:false,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:"💻",fitzpatrick_scale:false,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:"⌨",fitzpatrick_scale:false,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:"🖥",fitzpatrick_scale:false,category:"objects"},printer:{keywords:["paper","ink"],char:"🖨",fitzpatrick_scale:false,category:"objects"},computer_mouse:{keywords:["click"],char:"🖱",fitzpatrick_scale:false,category:"objects"},trackball:{keywords:["technology","trackpad"],char:"🖲",fitzpatrick_scale:false,category:"objects"},joystick:{keywords:["game","play"],char:"🕹",fitzpatrick_scale:false,category:"objects"},clamp:{keywords:["tool"],char:"🗜",fitzpatrick_scale:false,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:"💽",fitzpatrick_scale:false,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:"💾",fitzpatrick_scale:false,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:"💿",fitzpatrick_scale:false,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:"📀",fitzpatrick_scale:false,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:"📼",fitzpatrick_scale:false,category:"objects"},camera:{keywords:["gadgets","photography"],char:"📷",fitzpatrick_scale:false,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:"📸",fitzpatrick_scale:false,category:"objects"},video_camera:{keywords:["film","record"],char:"📹",fitzpatrick_scale:false,category:"objects"},movie_camera:{keywords:["film","record"],char:"🎥",fitzpatrick_scale:false,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:"📽",fitzpatrick_scale:false,category:"objects"},film_strip:{keywords:["movie"],char:"🎞",fitzpatrick_scale:false,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:"📞",fitzpatrick_scale:false,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:"☎️",fitzpatrick_scale:false,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:"📟",fitzpatrick_scale:false,category:"objects"},fax:{keywords:["communication","technology"],char:"📠",fitzpatrick_scale:false,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:"📺",fitzpatrick_scale:false,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:"📻",fitzpatrick_scale:false,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:"🎙",fitzpatrick_scale:false,category:"objects"},level_slider:{keywords:["scale"],char:"🎚",fitzpatrick_scale:false,category:"objects"},control_knobs:{keywords:["dial"],char:"🎛",fitzpatrick_scale:false,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:"🧭",fitzpatrick_scale:false,category:"objects"},stopwatch:{keywords:["time","deadline"],char:"⏱",fitzpatrick_scale:false,category:"objects"},timer_clock:{keywords:["alarm"],char:"⏲",fitzpatrick_scale:false,category:"objects"},alarm_clock:{keywords:["time","wake"],char:"⏰",fitzpatrick_scale:false,category:"objects"},mantelpiece_clock:{keywords:["time"],char:"🕰",fitzpatrick_scale:false,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:"⏳",fitzpatrick_scale:false,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:"⌛",fitzpatrick_scale:false,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:"📡",fitzpatrick_scale:false,category:"objects"},battery:{keywords:["power","energy","sustain"],char:"🔋",fitzpatrick_scale:false,category:"objects"},electric_plug:{keywords:["charger","power"],char:"🔌",fitzpatrick_scale:false,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:"💡",fitzpatrick_scale:false,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:"🔦",fitzpatrick_scale:false,category:"objects"},candle:{keywords:["fire","wax"],char:"🕯",fitzpatrick_scale:false,category:"objects"},fire_extinguisher:{keywords:["quench"],char:"🧯",fitzpatrick_scale:false,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:"🗑",fitzpatrick_scale:false,category:"objects"},oil_drum:{keywords:["barrell"],char:"🛢",fitzpatrick_scale:false,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:"💸",fitzpatrick_scale:false,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:"💵",fitzpatrick_scale:false,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:"💴",fitzpatrick_scale:false,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:"💶",fitzpatrick_scale:false,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:"💷",fitzpatrick_scale:false,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:"💰",fitzpatrick_scale:false,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:"💳",fitzpatrick_scale:false,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:"💎",fitzpatrick_scale:false,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:"⚖",fitzpatrick_scale:false,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:"🧰",fitzpatrick_scale:false,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:"🔧",fitzpatrick_scale:false,category:"objects"},hammer:{keywords:["tools","build","create"],char:"🔨",fitzpatrick_scale:false,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:"⚒",fitzpatrick_scale:false,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:"🛠",fitzpatrick_scale:false,category:"objects"},pick:{keywords:["tools","dig"],char:"⛏",fitzpatrick_scale:false,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:"🔩",fitzpatrick_scale:false,category:"objects"},gear:{keywords:["cog"],char:"⚙",fitzpatrick_scale:false,category:"objects"},brick:{keywords:["bricks"],char:"🧱",fitzpatrick_scale:false,category:"objects"},chains:{keywords:["lock","arrest"],char:"⛓",fitzpatrick_scale:false,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:"🧲",fitzpatrick_scale:false,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:"🔫",fitzpatrick_scale:false,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:"💣",fitzpatrick_scale:false,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:"🧨",fitzpatrick_scale:false,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:"🔪",fitzpatrick_scale:false,category:"objects"},dagger:{keywords:["weapon"],char:"🗡",fitzpatrick_scale:false,category:"objects"},crossed_swords:{keywords:["weapon"],char:"⚔",fitzpatrick_scale:false,category:"objects"},shield:{keywords:["protection","security"],char:"🛡",fitzpatrick_scale:false,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:"🚬",fitzpatrick_scale:false,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:"☠",fitzpatrick_scale:false,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:"⚰",fitzpatrick_scale:false,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:"⚱",fitzpatrick_scale:false,category:"objects"},amphora:{keywords:["vase","jar"],char:"🏺",fitzpatrick_scale:false,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:"🔮",fitzpatrick_scale:false,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:"📿",fitzpatrick_scale:false,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:"🧿",fitzpatrick_scale:false,category:"objects"},barber:{keywords:["hair","salon","style"],char:"💈",fitzpatrick_scale:false,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:"⚗",fitzpatrick_scale:false,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:"🔭",fitzpatrick_scale:false,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:"🔬",fitzpatrick_scale:false,category:"objects"},hole:{keywords:["embarrassing"],char:"🕳",fitzpatrick_scale:false,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:"💊",fitzpatrick_scale:false,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:"💉",fitzpatrick_scale:false,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:"🧬",fitzpatrick_scale:false,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:"🦠",fitzpatrick_scale:false,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:"🧫",fitzpatrick_scale:false,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:"🧪",fitzpatrick_scale:false,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:"🌡",fitzpatrick_scale:false,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:"🧹",fitzpatrick_scale:false,category:"objects"},basket:{keywords:["laundry"],char:"🧺",fitzpatrick_scale:false,category:"objects"},toilet_paper:{keywords:["roll"],char:"🧻",fitzpatrick_scale:false,category:"objects"},label:{keywords:["sale","tag"],char:"🏷",fitzpatrick_scale:false,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:"🔖",fitzpatrick_scale:false,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:"🚽",fitzpatrick_scale:false,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:"🚿",fitzpatrick_scale:false,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:"🛁",fitzpatrick_scale:false,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:"🧼",fitzpatrick_scale:false,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:"🧽",fitzpatrick_scale:false,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:"🧴",fitzpatrick_scale:false,category:"objects"},key:{keywords:["lock","door","password"],char:"🔑",fitzpatrick_scale:false,category:"objects"},old_key:{keywords:["lock","door","password"],char:"🗝",fitzpatrick_scale:false,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:"🛋",fitzpatrick_scale:false,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:"🛌",fitzpatrick_scale:true,category:"objects"},bed:{keywords:["sleep","rest"],char:"🛏",fitzpatrick_scale:false,category:"objects"},door:{keywords:["house","entry","exit"],char:"🚪",fitzpatrick_scale:false,category:"objects"},bellhop_bell:{keywords:["service"],char:"🛎",fitzpatrick_scale:false,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:"🧸",fitzpatrick_scale:false,category:"objects"},framed_picture:{keywords:["photography"],char:"🖼",fitzpatrick_scale:false,category:"objects"},world_map:{keywords:["location","direction"],char:"🗺",fitzpatrick_scale:false,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:"⛱",fitzpatrick_scale:false,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:"🗿",fitzpatrick_scale:false,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:"🛍",fitzpatrick_scale:false,category:"objects"},shopping_cart:{keywords:["trolley"],char:"🛒",fitzpatrick_scale:false,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:"🎈",fitzpatrick_scale:false,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:"🎏",fitzpatrick_scale:false,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:"🎀",fitzpatrick_scale:false,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:"🎁",fitzpatrick_scale:false,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:"🎊",fitzpatrick_scale:false,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:"🎉",fitzpatrick_scale:false,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:"🎎",fitzpatrick_scale:false,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:"🎐",fitzpatrick_scale:false,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:"🎌",fitzpatrick_scale:false,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:"🏮",fitzpatrick_scale:false,category:"objects"},red_envelope:{keywords:["gift"],char:"🧧",fitzpatrick_scale:false,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:"✉️",fitzpatrick_scale:false,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:"📩",fitzpatrick_scale:false,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:"📨",fitzpatrick_scale:false,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:"📧",fitzpatrick_scale:false,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:"💌",fitzpatrick_scale:false,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:"📮",fitzpatrick_scale:false,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:"📪",fitzpatrick_scale:false,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:"📫",fitzpatrick_scale:false,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:"📬",fitzpatrick_scale:false,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:"📭",fitzpatrick_scale:false,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:"📦",fitzpatrick_scale:false,category:"objects"},postal_horn:{keywords:["instrument","music"],char:"📯",fitzpatrick_scale:false,category:"objects"},inbox_tray:{keywords:["email","documents"],char:"📥",fitzpatrick_scale:false,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:"📤",fitzpatrick_scale:false,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:"📜",fitzpatrick_scale:false,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:"📃",fitzpatrick_scale:false,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:"📑",fitzpatrick_scale:false,category:"objects"},receipt:{keywords:["accounting","expenses"],char:"🧾",fitzpatrick_scale:false,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:"📊",fitzpatrick_scale:false,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:"📈",fitzpatrick_scale:false,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:"📉",fitzpatrick_scale:false,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:"📄",fitzpatrick_scale:false,category:"objects"},date:{keywords:["calendar","schedule"],char:"📅",fitzpatrick_scale:false,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:"📆",fitzpatrick_scale:false,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:"🗓",fitzpatrick_scale:false,category:"objects"},card_index:{keywords:["business","stationery"],char:"📇",fitzpatrick_scale:false,category:"objects"},card_file_box:{keywords:["business","stationery"],char:"🗃",fitzpatrick_scale:false,category:"objects"},ballot_box:{keywords:["election","vote"],char:"🗳",fitzpatrick_scale:false,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:"🗄",fitzpatrick_scale:false,category:"objects"},clipboard:{keywords:["stationery","documents"],char:"📋",fitzpatrick_scale:false,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:"🗒",fitzpatrick_scale:false,category:"objects"},file_folder:{keywords:["documents","business","office"],char:"📁",fitzpatrick_scale:false,category:"objects"},open_file_folder:{keywords:["documents","load"],char:"📂",fitzpatrick_scale:false,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:"🗂",fitzpatrick_scale:false,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:"🗞",fitzpatrick_scale:false,category:"objects"},newspaper:{keywords:["press","headline"],char:"📰",fitzpatrick_scale:false,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:"📓",fitzpatrick_scale:false,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:"📕",fitzpatrick_scale:false,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:"📗",fitzpatrick_scale:false,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:"📘",fitzpatrick_scale:false,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:"📙",fitzpatrick_scale:false,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:"📔",fitzpatrick_scale:false,category:"objects"},ledger:{keywords:["notes","paper"],char:"📒",fitzpatrick_scale:false,category:"objects"},books:{keywords:["literature","library","study"],char:"📚",fitzpatrick_scale:false,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:"📖",fitzpatrick_scale:false,category:"objects"},safety_pin:{keywords:["diaper"],char:"🧷",fitzpatrick_scale:false,category:"objects"},link:{keywords:["rings","url"],char:"🔗",fitzpatrick_scale:false,category:"objects"},paperclip:{keywords:["documents","stationery"],char:"📎",fitzpatrick_scale:false,category:"objects"},paperclips:{keywords:["documents","stationery"],char:"🖇",fitzpatrick_scale:false,category:"objects"},scissors:{keywords:["stationery","cut"],char:"✂️",fitzpatrick_scale:false,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:"📐",fitzpatrick_scale:false,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:"📏",fitzpatrick_scale:false,category:"objects"},abacus:{keywords:["calculation"],char:"🧮",fitzpatrick_scale:false,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:"📌",fitzpatrick_scale:false,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:"📍",fitzpatrick_scale:false,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:"🚩",fitzpatrick_scale:false,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:"🏳",fitzpatrick_scale:false,category:"objects"},black_flag:{keywords:["pirate"],char:"🏴",fitzpatrick_scale:false,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:"🏳️‍🌈",fitzpatrick_scale:false,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:"🔐",fitzpatrick_scale:false,category:"objects"},lock:{keywords:["security","password","padlock"],char:"🔒",fitzpatrick_scale:false,category:"objects"},unlock:{keywords:["privacy","security"],char:"🔓",fitzpatrick_scale:false,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:"🔏",fitzpatrick_scale:false,category:"objects"},pen:{keywords:["stationery","writing","write"],char:"🖊",fitzpatrick_scale:false,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:"🖋",fitzpatrick_scale:false,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:"✒️",fitzpatrick_scale:false,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:"📝",fitzpatrick_scale:false,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:"✏️",fitzpatrick_scale:false,category:"objects"},crayon:{keywords:["drawing","creativity"],char:"🖍",fitzpatrick_scale:false,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:"🖌",fitzpatrick_scale:false,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:"🔍",fitzpatrick_scale:false,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:"🔎",fitzpatrick_scale:false,category:"objects"},heart:{keywords:["love","like","valentines"],char:"❤️",fitzpatrick_scale:false,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:"🧡",fitzpatrick_scale:false,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:"💛",fitzpatrick_scale:false,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:"💚",fitzpatrick_scale:false,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:"💙",fitzpatrick_scale:false,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:"💜",fitzpatrick_scale:false,category:"symbols"},black_heart:{keywords:["evil"],char:"🖤",fitzpatrick_scale:false,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:"💔",fitzpatrick_scale:false,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:"❣",fitzpatrick_scale:false,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:"💕",fitzpatrick_scale:false,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:"💞",fitzpatrick_scale:false,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:"💓",fitzpatrick_scale:false,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:"💗",fitzpatrick_scale:false,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:"💖",fitzpatrick_scale:false,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:"💘",fitzpatrick_scale:false,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:"💝",fitzpatrick_scale:false,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:"💟",fitzpatrick_scale:false,category:"symbols"},peace_symbol:{keywords:["hippie"],char:"☮",fitzpatrick_scale:false,category:"symbols"},latin_cross:{keywords:["christianity"],char:"✝",fitzpatrick_scale:false,category:"symbols"},star_and_crescent:{keywords:["islam"],char:"☪",fitzpatrick_scale:false,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"🕉",fitzpatrick_scale:false,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"☸",fitzpatrick_scale:false,category:"symbols"},star_of_david:{keywords:["judaism"],char:"✡",fitzpatrick_scale:false,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:"🔯",fitzpatrick_scale:false,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:"🕎",fitzpatrick_scale:false,category:"symbols"},yin_yang:{keywords:["balance"],char:"☯",fitzpatrick_scale:false,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:"☦",fitzpatrick_scale:false,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:"🛐",fitzpatrick_scale:false,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:"⛎",fitzpatrick_scale:false,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:"♈",fitzpatrick_scale:false,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:"♉",fitzpatrick_scale:false,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:"♊",fitzpatrick_scale:false,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:"♋",fitzpatrick_scale:false,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:"♌",fitzpatrick_scale:false,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:"♍",fitzpatrick_scale:false,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:"♎",fitzpatrick_scale:false,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:"♏",fitzpatrick_scale:false,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:"♐",fitzpatrick_scale:false,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:"♑",fitzpatrick_scale:false,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:"♒",fitzpatrick_scale:false,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:"♓",fitzpatrick_scale:false,category:"symbols"},id:{keywords:["purple-square","words"],char:"🆔",fitzpatrick_scale:false,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:"⚛",fitzpatrick_scale:false,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:"🈳",fitzpatrick_scale:false,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:"🈹",fitzpatrick_scale:false,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:"☢",fitzpatrick_scale:false,category:"symbols"},biohazard:{keywords:["danger"],char:"☣",fitzpatrick_scale:false,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:"📴",fitzpatrick_scale:false,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:"📳",fitzpatrick_scale:false,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:"🈶",fitzpatrick_scale:false,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:"🈚",fitzpatrick_scale:false,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:"🈸",fitzpatrick_scale:false,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:"🈺",fitzpatrick_scale:false,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:"🈷️",fitzpatrick_scale:false,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:"✴️",fitzpatrick_scale:false,category:"symbols"},vs:{keywords:["words","orange-square"],char:"🆚",fitzpatrick_scale:false,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:"🉑",fitzpatrick_scale:false,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:"💮",fitzpatrick_scale:false,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:"🉐",fitzpatrick_scale:false,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:"㊙️",fitzpatrick_scale:false,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:"㊗️",fitzpatrick_scale:false,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:"🈴",fitzpatrick_scale:false,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:"🈵",fitzpatrick_scale:false,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:"🈲",fitzpatrick_scale:false,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:"🅰️",fitzpatrick_scale:false,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:"🅱️",fitzpatrick_scale:false,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:"🆎",fitzpatrick_scale:false,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:"🆑",fitzpatrick_scale:false,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:"🅾️",fitzpatrick_scale:false,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:"🆘",fitzpatrick_scale:false,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:"⛔",fitzpatrick_scale:false,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:"📛",fitzpatrick_scale:false,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:"🚫",fitzpatrick_scale:false,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:"❌",fitzpatrick_scale:false,category:"symbols"},o:{keywords:["circle","round"],char:"⭕",fitzpatrick_scale:false,category:"symbols"},stop_sign:{keywords:["stop"],char:"🛑",fitzpatrick_scale:false,category:"symbols"},anger:{keywords:["angry","mad"],char:"💢",fitzpatrick_scale:false,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:"♨️",fitzpatrick_scale:false,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:"🚷",fitzpatrick_scale:false,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:"🚯",fitzpatrick_scale:false,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:"🚳",fitzpatrick_scale:false,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:"🚱",fitzpatrick_scale:false,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:"🔞",fitzpatrick_scale:false,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:"📵",fitzpatrick_scale:false,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:"❗",fitzpatrick_scale:false,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:"❕",fitzpatrick_scale:false,category:"symbols"},question:{keywords:["doubt","confused"],char:"❓",fitzpatrick_scale:false,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:"❔",fitzpatrick_scale:false,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:"‼️",fitzpatrick_scale:false,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:"⁉️",fitzpatrick_scale:false,category:"symbols"},100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:"💯",fitzpatrick_scale:false,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:"🔅",fitzpatrick_scale:false,category:"symbols"},high_brightness:{keywords:["sun","light"],char:"🔆",fitzpatrick_scale:false,category:"symbols"},trident:{keywords:["weapon","spear"],char:"🔱",fitzpatrick_scale:false,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:"⚜",fitzpatrick_scale:false,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:"〽️",fitzpatrick_scale:false,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:"⚠️",fitzpatrick_scale:false,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:"🚸",fitzpatrick_scale:false,category:"symbols"},beginner:{keywords:["badge","shield"],char:"🔰",fitzpatrick_scale:false,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:"♻️",fitzpatrick_scale:false,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:"🈯",fitzpatrick_scale:false,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:"💹",fitzpatrick_scale:false,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:"❇️",fitzpatrick_scale:false,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:"✳️",fitzpatrick_scale:false,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:"❎",fitzpatrick_scale:false,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:"✅",fitzpatrick_scale:false,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:"💠",fitzpatrick_scale:false,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:"🌀",fitzpatrick_scale:false,category:"symbols"},loop:{keywords:["tape","cassette"],char:"➿",fitzpatrick_scale:false,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:"🌐",fitzpatrick_scale:false,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:"Ⓜ️",fitzpatrick_scale:false,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:"🏧",fitzpatrick_scale:false,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:"🈂️",fitzpatrick_scale:false,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:"🛂",fitzpatrick_scale:false,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:"🛃",fitzpatrick_scale:false,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:"🛄",fitzpatrick_scale:false,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:"🛅",fitzpatrick_scale:false,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:"♿",fitzpatrick_scale:false,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:"🚭",fitzpatrick_scale:false,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:"🚾",fitzpatrick_scale:false,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:"🅿️",fitzpatrick_scale:false,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:"🚰",fitzpatrick_scale:false,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:"🚹",fitzpatrick_scale:false,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:"🚺",fitzpatrick_scale:false,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:"🚼",fitzpatrick_scale:false,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:"🚻",fitzpatrick_scale:false,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:"🚮",fitzpatrick_scale:false,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:"🎦",fitzpatrick_scale:false,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:"📶",fitzpatrick_scale:false,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:"🈁",fitzpatrick_scale:false,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:"🆖",fitzpatrick_scale:false,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:"🆗",fitzpatrick_scale:false,category:"symbols"},up:{keywords:["blue-square","above","high"],char:"🆙",fitzpatrick_scale:false,category:"symbols"},cool:{keywords:["words","blue-square"],char:"🆒",fitzpatrick_scale:false,category:"symbols"},new:{keywords:["blue-square","words","start"],char:"🆕",fitzpatrick_scale:false,category:"symbols"},free:{keywords:["blue-square","words"],char:"🆓",fitzpatrick_scale:false,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:"0️⃣",fitzpatrick_scale:false,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:"1️⃣",fitzpatrick_scale:false,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:"2️⃣",fitzpatrick_scale:false,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:"3️⃣",fitzpatrick_scale:false,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:"4️⃣",fitzpatrick_scale:false,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:"5️⃣",fitzpatrick_scale:false,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:"6️⃣",fitzpatrick_scale:false,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:"7️⃣",fitzpatrick_scale:false,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:"8️⃣",fitzpatrick_scale:false,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:"9️⃣",fitzpatrick_scale:false,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:"🔟",fitzpatrick_scale:false,category:"symbols"},asterisk:{keywords:["star","keycap"],char:"*⃣",fitzpatrick_scale:false,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:"🔢",fitzpatrick_scale:false,category:"symbols"},eject_button:{keywords:["blue-square"],char:"⏏️",fitzpatrick_scale:false,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:"▶️",fitzpatrick_scale:false,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:"⏸",fitzpatrick_scale:false,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:"⏭",fitzpatrick_scale:false,category:"symbols"},stop_button:{keywords:["blue-square"],char:"⏹",fitzpatrick_scale:false,category:"symbols"},record_button:{keywords:["blue-square"],char:"⏺",fitzpatrick_scale:false,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:"⏯",fitzpatrick_scale:false,category:"symbols"},previous_track_button:{keywords:["backward"],char:"⏮",fitzpatrick_scale:false,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:"⏩",fitzpatrick_scale:false,category:"symbols"},rewind:{keywords:["play","blue-square"],char:"⏪",fitzpatrick_scale:false,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:"🔀",fitzpatrick_scale:false,category:"symbols"},repeat:{keywords:["loop","record"],char:"🔁",fitzpatrick_scale:false,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:"🔂",fitzpatrick_scale:false,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:"◀️",fitzpatrick_scale:false,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:"🔼",fitzpatrick_scale:false,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:"🔽",fitzpatrick_scale:false,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:"⏫",fitzpatrick_scale:false,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:"⏬",fitzpatrick_scale:false,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:"➡️",fitzpatrick_scale:false,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:"⬅️",fitzpatrick_scale:false,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:"⬆️",fitzpatrick_scale:false,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:"⬇️",fitzpatrick_scale:false,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:"↗️",fitzpatrick_scale:false,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:"↘️",fitzpatrick_scale:false,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:"↙️",fitzpatrick_scale:false,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:"↖️",fitzpatrick_scale:false,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:"↕️",fitzpatrick_scale:false,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:"↔️",fitzpatrick_scale:false,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:"🔄",fitzpatrick_scale:false,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:"↪️",fitzpatrick_scale:false,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:"↩️",fitzpatrick_scale:false,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:"⤴️",fitzpatrick_scale:false,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:"⤵️",fitzpatrick_scale:false,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:"#️⃣",fitzpatrick_scale:false,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:"ℹ️",fitzpatrick_scale:false,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:"🔤",fitzpatrick_scale:false,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:"🔡",fitzpatrick_scale:false,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:"🔠",fitzpatrick_scale:false,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:"🔣",fitzpatrick_scale:false,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:"🎵",fitzpatrick_scale:false,category:"symbols"},notes:{keywords:["music","score"],char:"🎶",fitzpatrick_scale:false,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:"〰️",fitzpatrick_scale:false,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:"➰",fitzpatrick_scale:false,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:"✔️",fitzpatrick_scale:false,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:"🔃",fitzpatrick_scale:false,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:"➕",fitzpatrick_scale:false,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:"➖",fitzpatrick_scale:false,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:"➗",fitzpatrick_scale:false,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:"✖️",fitzpatrick_scale:false,category:"symbols"},infinity:{keywords:["forever"],char:"♾",fitzpatrick_scale:false,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:"💲",fitzpatrick_scale:false,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:"💱",fitzpatrick_scale:false,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:"©️",fitzpatrick_scale:false,category:"symbols"},registered:{keywords:["alphabet","circle"],char:"®️",fitzpatrick_scale:false,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:"™️",fitzpatrick_scale:false,category:"symbols"},end:{keywords:["words","arrow"],char:"🔚",fitzpatrick_scale:false,category:"symbols"},back:{keywords:["arrow","words","return"],char:"🔙",fitzpatrick_scale:false,category:"symbols"},on:{keywords:["arrow","words"],char:"🔛",fitzpatrick_scale:false,category:"symbols"},top:{keywords:["words","blue-square"],char:"🔝",fitzpatrick_scale:false,category:"symbols"},soon:{keywords:["arrow","words"],char:"🔜",fitzpatrick_scale:false,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:"☑️",fitzpatrick_scale:false,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:"🔘",fitzpatrick_scale:false,category:"symbols"},white_circle:{keywords:["shape","round"],char:"⚪",fitzpatrick_scale:false,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:"⚫",fitzpatrick_scale:false,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:"🔴",fitzpatrick_scale:false,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:"🔵",fitzpatrick_scale:false,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:"🔸",fitzpatrick_scale:false,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:"🔹",fitzpatrick_scale:false,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:"🔶",fitzpatrick_scale:false,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:"🔷",fitzpatrick_scale:false,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:"🔺",fitzpatrick_scale:false,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:"▪️",fitzpatrick_scale:false,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:"▫️",fitzpatrick_scale:false,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:"⬛",fitzpatrick_scale:false,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:"⬜",fitzpatrick_scale:false,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:"🔻",fitzpatrick_scale:false,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:"◼️",fitzpatrick_scale:false,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:"◻️",fitzpatrick_scale:false,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:"◾",fitzpatrick_scale:false,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:"◽",fitzpatrick_scale:false,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:"🔲",fitzpatrick_scale:false,category:"symbols"},white_square_button:{keywords:["shape","input"],char:"🔳",fitzpatrick_scale:false,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:"🔈",fitzpatrick_scale:false,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:"🔉",fitzpatrick_scale:false,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:"🔊",fitzpatrick_scale:false,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:"🔇",fitzpatrick_scale:false,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:"📣",fitzpatrick_scale:false,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:"📢",fitzpatrick_scale:false,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:"🔔",fitzpatrick_scale:false,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:"🔕",fitzpatrick_scale:false,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:"🃏",fitzpatrick_scale:false,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:"🀄",fitzpatrick_scale:false,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:"♠️",fitzpatrick_scale:false,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:"♣️",fitzpatrick_scale:false,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:"♥️",fitzpatrick_scale:false,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:"♦️",fitzpatrick_scale:false,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:"🎴",fitzpatrick_scale:false,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:"💭",fitzpatrick_scale:false,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:"🗯",fitzpatrick_scale:false,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:"💬",fitzpatrick_scale:false,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:"🗨",fitzpatrick_scale:false,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:"🕐",fitzpatrick_scale:false,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:"🕑",fitzpatrick_scale:false,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:"🕒",fitzpatrick_scale:false,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:"🕓",fitzpatrick_scale:false,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:"🕔",fitzpatrick_scale:false,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:"🕕",fitzpatrick_scale:false,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:"🕖",fitzpatrick_scale:false,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:"🕗",fitzpatrick_scale:false,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:"🕘",fitzpatrick_scale:false,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:"🕙",fitzpatrick_scale:false,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:"🕚",fitzpatrick_scale:false,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:"🕛",fitzpatrick_scale:false,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:"🕜",fitzpatrick_scale:false,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:"🕝",fitzpatrick_scale:false,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:"🕞",fitzpatrick_scale:false,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:"🕟",fitzpatrick_scale:false,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:"🕠",fitzpatrick_scale:false,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:"🕡",fitzpatrick_scale:false,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:"🕢",fitzpatrick_scale:false,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:"🕣",fitzpatrick_scale:false,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:"🕤",fitzpatrick_scale:false,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:"🕥",fitzpatrick_scale:false,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:"🕦",fitzpatrick_scale:false,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:"🕧",fitzpatrick_scale:false,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:"🇦🇫",fitzpatrick_scale:false,category:"flags"},aland_islands:{keywords:["Åland","islands","flag","nation","country","banner"],char:"🇦🇽",fitzpatrick_scale:false,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:"🇦🇱",fitzpatrick_scale:false,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:"🇩🇿",fitzpatrick_scale:false,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:"🇦🇸",fitzpatrick_scale:false,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:"🇦🇩",fitzpatrick_scale:false,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:"🇦🇴",fitzpatrick_scale:false,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:"🇦🇮",fitzpatrick_scale:false,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:"🇦🇶",fitzpatrick_scale:false,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:"🇦🇬",fitzpatrick_scale:false,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:"🇦🇷",fitzpatrick_scale:false,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:"🇦🇲",fitzpatrick_scale:false,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:"🇦🇼",fitzpatrick_scale:false,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:"🇦🇺",fitzpatrick_scale:false,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:"🇦🇹",fitzpatrick_scale:false,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:"🇦🇿",fitzpatrick_scale:false,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:"🇧🇸",fitzpatrick_scale:false,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:"🇧🇭",fitzpatrick_scale:false,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:"🇧🇩",fitzpatrick_scale:false,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:"🇧🇧",fitzpatrick_scale:false,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:"🇧🇾",fitzpatrick_scale:false,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:"🇧🇪",fitzpatrick_scale:false,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:"🇧🇿",fitzpatrick_scale:false,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:"🇧🇯",fitzpatrick_scale:false,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:"🇧🇲",fitzpatrick_scale:false,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:"🇧🇹",fitzpatrick_scale:false,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:"🇧🇴",fitzpatrick_scale:false,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:"🇧🇶",fitzpatrick_scale:false,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:"🇧🇦",fitzpatrick_scale:false,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:"🇧🇼",fitzpatrick_scale:false,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:"🇧🇷",fitzpatrick_scale:false,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:"🇮🇴",fitzpatrick_scale:false,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:"🇻🇬",fitzpatrick_scale:false,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:"🇧🇳",fitzpatrick_scale:false,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:"🇧🇬",fitzpatrick_scale:false,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:"🇧🇫",fitzpatrick_scale:false,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:"🇧🇮",fitzpatrick_scale:false,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:"🇨🇻",fitzpatrick_scale:false,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:"🇰🇭",fitzpatrick_scale:false,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:"🇨🇲",fitzpatrick_scale:false,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:"🇨🇦",fitzpatrick_scale:false,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:"🇮🇨",fitzpatrick_scale:false,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:"🇰🇾",fitzpatrick_scale:false,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:"🇨🇫",fitzpatrick_scale:false,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:"🇹🇩",fitzpatrick_scale:false,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:"🇨🇱",fitzpatrick_scale:false,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:"🇨🇳",fitzpatrick_scale:false,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:"🇨🇽",fitzpatrick_scale:false,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:"🇨🇨",fitzpatrick_scale:false,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:"🇨🇴",fitzpatrick_scale:false,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:"🇰🇲",fitzpatrick_scale:false,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:"🇨🇬",fitzpatrick_scale:false,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:"🇨🇩",fitzpatrick_scale:false,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:"🇨🇰",fitzpatrick_scale:false,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:"🇨🇷",fitzpatrick_scale:false,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:"🇭🇷",fitzpatrick_scale:false,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:"🇨🇺",fitzpatrick_scale:false,category:"flags"},curacao:{keywords:["curaçao","flag","nation","country","banner"],char:"🇨🇼",fitzpatrick_scale:false,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:"🇨🇾",fitzpatrick_scale:false,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:"🇨🇿",fitzpatrick_scale:false,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:"🇩🇰",fitzpatrick_scale:false,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:"🇩🇯",fitzpatrick_scale:false,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:"🇩🇲",fitzpatrick_scale:false,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:"🇩🇴",fitzpatrick_scale:false,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:"🇪🇨",fitzpatrick_scale:false,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:"🇪🇬",fitzpatrick_scale:false,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:"🇸🇻",fitzpatrick_scale:false,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:"🇬🇶",fitzpatrick_scale:false,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:"🇪🇷",fitzpatrick_scale:false,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:"🇪🇪",fitzpatrick_scale:false,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:"🇪🇹",fitzpatrick_scale:false,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:"🇪🇺",fitzpatrick_scale:false,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:"🇫🇰",fitzpatrick_scale:false,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:"🇫🇴",fitzpatrick_scale:false,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:"🇫🇯",fitzpatrick_scale:false,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:"🇫🇮",fitzpatrick_scale:false,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:"🇫🇷",fitzpatrick_scale:false,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:"🇬🇫",fitzpatrick_scale:false,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:"🇵🇫",fitzpatrick_scale:false,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:"🇹🇫",fitzpatrick_scale:false,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:"🇬🇦",fitzpatrick_scale:false,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:"🇬🇲",fitzpatrick_scale:false,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:"🇬🇪",fitzpatrick_scale:false,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:"🇩🇪",fitzpatrick_scale:false,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:"🇬🇭",fitzpatrick_scale:false,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:"🇬🇮",fitzpatrick_scale:false,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:"🇬🇷",fitzpatrick_scale:false,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:"🇬🇱",fitzpatrick_scale:false,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:"🇬🇩",fitzpatrick_scale:false,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:"🇬🇵",fitzpatrick_scale:false,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:"🇬🇺",fitzpatrick_scale:false,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:"🇬🇹",fitzpatrick_scale:false,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:"🇬🇬",fitzpatrick_scale:false,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:"🇬🇳",fitzpatrick_scale:false,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:"🇬🇼",fitzpatrick_scale:false,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:"🇬🇾",fitzpatrick_scale:false,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:"🇭🇹",fitzpatrick_scale:false,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:"🇭🇳",fitzpatrick_scale:false,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:"🇭🇰",fitzpatrick_scale:false,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:"🇭🇺",fitzpatrick_scale:false,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:"🇮🇸",fitzpatrick_scale:false,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:"🇮🇳",fitzpatrick_scale:false,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:"🇮🇩",fitzpatrick_scale:false,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:"🇮🇷",fitzpatrick_scale:false,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:"🇮🇶",fitzpatrick_scale:false,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:"🇮🇪",fitzpatrick_scale:false,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:"🇮🇲",fitzpatrick_scale:false,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:"🇮🇱",fitzpatrick_scale:false,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:"🇮🇹",fitzpatrick_scale:false,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:"🇨🇮",fitzpatrick_scale:false,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:"🇯🇲",fitzpatrick_scale:false,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:"🇯🇵",fitzpatrick_scale:false,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:"🇯🇪",fitzpatrick_scale:false,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:"🇯🇴",fitzpatrick_scale:false,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:"🇰🇿",fitzpatrick_scale:false,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:"🇰🇪",fitzpatrick_scale:false,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:"🇰🇮",fitzpatrick_scale:false,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:"🇽🇰",fitzpatrick_scale:false,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:"🇰🇼",fitzpatrick_scale:false,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:"🇰🇬",fitzpatrick_scale:false,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:"🇱🇦",fitzpatrick_scale:false,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:"🇱🇻",fitzpatrick_scale:false,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:"🇱🇧",fitzpatrick_scale:false,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:"🇱🇸",fitzpatrick_scale:false,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:"🇱🇷",fitzpatrick_scale:false,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:"🇱🇾",fitzpatrick_scale:false,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:"🇱🇮",fitzpatrick_scale:false,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:"🇱🇹",fitzpatrick_scale:false,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:"🇱🇺",fitzpatrick_scale:false,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:"🇲🇴",fitzpatrick_scale:false,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:"🇲🇰",fitzpatrick_scale:false,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:"🇲🇬",fitzpatrick_scale:false,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:"🇲🇼",fitzpatrick_scale:false,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:"🇲🇾",fitzpatrick_scale:false,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:"🇲🇻",fitzpatrick_scale:false,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:"🇲🇱",fitzpatrick_scale:false,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:"🇲🇹",fitzpatrick_scale:false,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:"🇲🇭",fitzpatrick_scale:false,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:"🇲🇶",fitzpatrick_scale:false,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:"🇲🇷",fitzpatrick_scale:false,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:"🇲🇺",fitzpatrick_scale:false,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:"🇾🇹",fitzpatrick_scale:false,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:"🇲🇽",fitzpatrick_scale:false,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:"🇫🇲",fitzpatrick_scale:false,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:"🇲🇩",fitzpatrick_scale:false,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:"🇲🇨",fitzpatrick_scale:false,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:"🇲🇳",fitzpatrick_scale:false,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:"🇲🇪",fitzpatrick_scale:false,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:"🇲🇸",fitzpatrick_scale:false,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:"🇲🇦",fitzpatrick_scale:false,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:"🇲🇿",fitzpatrick_scale:false,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:"🇲🇲",fitzpatrick_scale:false,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:"🇳🇦",fitzpatrick_scale:false,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:"🇳🇷",fitzpatrick_scale:false,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:"🇳🇵",fitzpatrick_scale:false,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:"🇳🇱",fitzpatrick_scale:false,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:"🇳🇨",fitzpatrick_scale:false,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:"🇳🇿",fitzpatrick_scale:false,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:"🇳🇮",fitzpatrick_scale:false,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:"🇳🇪",fitzpatrick_scale:false,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:"🇳🇬",fitzpatrick_scale:false,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:"🇳🇺",fitzpatrick_scale:false,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:"🇳🇫",fitzpatrick_scale:false,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:"🇲🇵",fitzpatrick_scale:false,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:"🇰🇵",fitzpatrick_scale:false,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:"🇳🇴",fitzpatrick_scale:false,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:"🇴🇲",fitzpatrick_scale:false,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:"🇵🇰",fitzpatrick_scale:false,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:"🇵🇼",fitzpatrick_scale:false,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:"🇵🇸",fitzpatrick_scale:false,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:"🇵🇦",fitzpatrick_scale:false,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:"🇵🇬",fitzpatrick_scale:false,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:"🇵🇾",fitzpatrick_scale:false,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:"🇵🇪",fitzpatrick_scale:false,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:"🇵🇭",fitzpatrick_scale:false,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:"🇵🇳",fitzpatrick_scale:false,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:"🇵🇱",fitzpatrick_scale:false,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:"🇵🇹",fitzpatrick_scale:false,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:"🇵🇷",fitzpatrick_scale:false,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:"🇶🇦",fitzpatrick_scale:false,category:"flags"},reunion:{keywords:["réunion","flag","nation","country","banner"],char:"🇷🇪",fitzpatrick_scale:false,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:"🇷🇴",fitzpatrick_scale:false,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:"🇷🇺",fitzpatrick_scale:false,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:"🇷🇼",fitzpatrick_scale:false,category:"flags"},st_barthelemy:{keywords:["saint","barthélemy","flag","nation","country","banner"],char:"🇧🇱",fitzpatrick_scale:false,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:"🇸🇭",fitzpatrick_scale:false,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:"🇰🇳",fitzpatrick_scale:false,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:"🇱🇨",fitzpatrick_scale:false,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:"🇵🇲",fitzpatrick_scale:false,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:"🇻🇨",fitzpatrick_scale:false,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:"🇼🇸",fitzpatrick_scale:false,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:"🇸🇲",fitzpatrick_scale:false,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:"🇸🇹",fitzpatrick_scale:false,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:"🇸🇦",fitzpatrick_scale:false,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:"🇸🇳",fitzpatrick_scale:false,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:"🇷🇸",fitzpatrick_scale:false,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:"🇸🇨",fitzpatrick_scale:false,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:"🇸🇱",fitzpatrick_scale:false,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:"🇸🇬",fitzpatrick_scale:false,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:"🇸🇽",fitzpatrick_scale:false,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:"🇸🇰",fitzpatrick_scale:false,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:"🇸🇮",fitzpatrick_scale:false,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:"🇸🇧",fitzpatrick_scale:false,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:"🇸🇴",fitzpatrick_scale:false,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:"🇿🇦",fitzpatrick_scale:false,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:"🇬🇸",fitzpatrick_scale:false,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:"🇰🇷",fitzpatrick_scale:false,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:"🇸🇸",fitzpatrick_scale:false,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:"🇪🇸",fitzpatrick_scale:false,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:"🇱🇰",fitzpatrick_scale:false,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:"🇸🇩",fitzpatrick_scale:false,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:"🇸🇷",fitzpatrick_scale:false,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:"🇸🇿",fitzpatrick_scale:false,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:"🇸🇪",fitzpatrick_scale:false,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:"🇨🇭",fitzpatrick_scale:false,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:"🇸🇾",fitzpatrick_scale:false,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:"🇹🇼",fitzpatrick_scale:false,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:"🇹🇯",fitzpatrick_scale:false,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:"🇹🇿",fitzpatrick_scale:false,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:"🇹🇭",fitzpatrick_scale:false,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:"🇹🇱",fitzpatrick_scale:false,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:"🇹🇬",fitzpatrick_scale:false,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:"🇹🇰",fitzpatrick_scale:false,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:"🇹🇴",fitzpatrick_scale:false,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:"🇹🇹",fitzpatrick_scale:false,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:"🇹🇳",fitzpatrick_scale:false,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:"🇹🇷",fitzpatrick_scale:false,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:"🇹🇲",fitzpatrick_scale:false,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:"🇹🇨",fitzpatrick_scale:false,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:"🇹🇻",fitzpatrick_scale:false,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:"🇺🇬",fitzpatrick_scale:false,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:"🇺🇦",fitzpatrick_scale:false,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:"🇦🇪",fitzpatrick_scale:false,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:"🇬🇧",fitzpatrick_scale:false,category:"flags"},england:{keywords:["flag","english"],char:"🏴󠁧󠁢󠁥󠁮󠁧󠁿",fitzpatrick_scale:false,category:"flags"},scotland:{keywords:["flag","scottish"],char:"🏴󠁧󠁢󠁳󠁣󠁴󠁿",fitzpatrick_scale:false,category:"flags"},wales:{keywords:["flag","welsh"],char:"🏴󠁧󠁢󠁷󠁬󠁳󠁿",fitzpatrick_scale:false,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:"🇺🇸",fitzpatrick_scale:false,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:"🇻🇮",fitzpatrick_scale:false,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:"🇺🇾",fitzpatrick_scale:false,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:"🇺🇿",fitzpatrick_scale:false,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:"🇻🇺",fitzpatrick_scale:false,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:"🇻🇦",fitzpatrick_scale:false,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:"🇻🇪",fitzpatrick_scale:false,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:"🇻🇳",fitzpatrick_scale:false,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:"🇼🇫",fitzpatrick_scale:false,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:"🇪🇭",fitzpatrick_scale:false,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:"🇾🇪",fitzpatrick_scale:false,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:"🇿🇲",fitzpatrick_scale:false,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:"🇿🇼",fitzpatrick_scale:false,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:"🇺🇳",fitzpatrick_scale:false,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:"🏴‍☠️",fitzpatrick_scale:false,category:"flags"}}); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.min.js b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.min.js new file mode 100644 index 0000000..5a1c491 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.min.js @@ -0,0 +1,2 @@ +// Source: npm package: emojilib, file:emojis.json +window.tinymce.Resource.add("tinymce.plugins.emoticons",{grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:"\u{1f600}",fitzpatrick_scale:!1,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:"\u{1f62c}",fitzpatrick_scale:!1,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:"\u{1f601}",fitzpatrick_scale:!1,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:"\u{1f602}",fitzpatrick_scale:!1,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:"\u{1f923}",fitzpatrick_scale:!1,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:"\u{1f973}",fitzpatrick_scale:!1,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:"\u{1f603}",fitzpatrick_scale:!1,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:"\u{1f604}",fitzpatrick_scale:!1,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:"\u{1f605}",fitzpatrick_scale:!1,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:"\u{1f606}",fitzpatrick_scale:!1,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:"\u{1f607}",fitzpatrick_scale:!1,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:"\u{1f609}",fitzpatrick_scale:!1,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:"\u{1f60a}",fitzpatrick_scale:!1,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:"\u{1f642}",fitzpatrick_scale:!1,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:"\u{1f643}",fitzpatrick_scale:!1,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:"\u263a\ufe0f",fitzpatrick_scale:!1,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:"\u{1f60b}",fitzpatrick_scale:!1,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:"\u{1f60c}",fitzpatrick_scale:!1,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:"\u{1f60d}",fitzpatrick_scale:!1,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:"\u{1f970}",fitzpatrick_scale:!1,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"\u{1f618}",fitzpatrick_scale:!1,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:"\u{1f617}",fitzpatrick_scale:!1,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:"\u{1f619}",fitzpatrick_scale:!1,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"\u{1f61a}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:"\u{1f61c}",fitzpatrick_scale:!1,category:"people"},zany:{keywords:["face","goofy","crazy"],char:"\u{1f92a}",fitzpatrick_scale:!1,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:"\u{1f928}",fitzpatrick_scale:!1,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:"\u{1f9d0}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:"\u{1f61d}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:"\u{1f61b}",fitzpatrick_scale:!1,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:"\u{1f911}",fitzpatrick_scale:!1,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:"\u{1f913}",fitzpatrick_scale:!1,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:"\u{1f60e}",fitzpatrick_scale:!1,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:"\u{1f929}",fitzpatrick_scale:!1,category:"people"},clown_face:{keywords:["face"],char:"\u{1f921}",fitzpatrick_scale:!1,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:"\u{1f920}",fitzpatrick_scale:!1,category:"people"},hugs:{keywords:["face","smile","hug"],char:"\u{1f917}",fitzpatrick_scale:!1,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:"\u{1f60f}",fitzpatrick_scale:!1,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:"\u{1f636}",fitzpatrick_scale:!1,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:"\u{1f610}",fitzpatrick_scale:!1,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:"\u{1f611}",fitzpatrick_scale:!1,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:"\u{1f612}",fitzpatrick_scale:!1,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:"\u{1f644}",fitzpatrick_scale:!1,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:"\u{1f914}",fitzpatrick_scale:!1,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:"\u{1f925}",fitzpatrick_scale:!1,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:"\u{1f92d}",fitzpatrick_scale:!1,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:"\u{1f92b}",fitzpatrick_scale:!1,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:"\u{1f92c}",fitzpatrick_scale:!1,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:"\u{1f92f}",fitzpatrick_scale:!1,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:"\u{1f633}",fitzpatrick_scale:!1,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:"\u{1f61e}",fitzpatrick_scale:!1,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:"\u{1f61f}",fitzpatrick_scale:!1,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:"\u{1f620}",fitzpatrick_scale:!1,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:"\u{1f621}",fitzpatrick_scale:!1,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:"\u{1f614}",fitzpatrick_scale:!1,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:"\u{1f615}",fitzpatrick_scale:!1,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:"\u{1f641}",fitzpatrick_scale:!1,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:"\u2639",fitzpatrick_scale:!1,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:"\u{1f623}",fitzpatrick_scale:!1,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:"\u{1f616}",fitzpatrick_scale:!1,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:"\u{1f62b}",fitzpatrick_scale:!1,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:"\u{1f629}",fitzpatrick_scale:!1,category:"people"},pleading:{keywords:["face","begging","mercy"],char:"\u{1f97a}",fitzpatrick_scale:!1,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:"\u{1f624}",fitzpatrick_scale:!1,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:"\u{1f62e}",fitzpatrick_scale:!1,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:"\u{1f631}",fitzpatrick_scale:!1,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:"\u{1f628}",fitzpatrick_scale:!1,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:"\u{1f630}",fitzpatrick_scale:!1,category:"people"},hushed:{keywords:["face","woo","shh"],char:"\u{1f62f}",fitzpatrick_scale:!1,category:"people"},frowning:{keywords:["face","aw","what"],char:"\u{1f626}",fitzpatrick_scale:!1,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:"\u{1f627}",fitzpatrick_scale:!1,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:"\u{1f622}",fitzpatrick_scale:!1,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:"\u{1f625}",fitzpatrick_scale:!1,category:"people"},drooling_face:{keywords:["face"],char:"\u{1f924}",fitzpatrick_scale:!1,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:"\u{1f62a}",fitzpatrick_scale:!1,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:"\u{1f613}",fitzpatrick_scale:!1,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:"\u{1f975}",fitzpatrick_scale:!1,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:"\u{1f976}",fitzpatrick_scale:!1,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:"\u{1f62d}",fitzpatrick_scale:!1,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:"\u{1f635}",fitzpatrick_scale:!1,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:"\u{1f632}",fitzpatrick_scale:!1,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:"\u{1f910}",fitzpatrick_scale:!1,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:"\u{1f922}",fitzpatrick_scale:!1,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:"\u{1f927}",fitzpatrick_scale:!1,category:"people"},vomiting:{keywords:["face","sick"],char:"\u{1f92e}",fitzpatrick_scale:!1,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:"\u{1f637}",fitzpatrick_scale:!1,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:"\u{1f912}",fitzpatrick_scale:!1,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:"\u{1f915}",fitzpatrick_scale:!1,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:"\u{1f974}",fitzpatrick_scale:!1,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:"\u{1f634}",fitzpatrick_scale:!1,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:"\u{1f4a4}",fitzpatrick_scale:!1,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:"\u{1f4a9}",fitzpatrick_scale:!1,category:"people"},smiling_imp:{keywords:["devil","horns"],char:"\u{1f608}",fitzpatrick_scale:!1,category:"people"},imp:{keywords:["devil","angry","horns"],char:"\u{1f47f}",fitzpatrick_scale:!1,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:"\u{1f479}",fitzpatrick_scale:!1,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:"\u{1f47a}",fitzpatrick_scale:!1,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:"\u{1f480}",fitzpatrick_scale:!1,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:"\u{1f47b}",fitzpatrick_scale:!1,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:"\u{1f47d}",fitzpatrick_scale:!1,category:"people"},robot:{keywords:["computer","machine","bot"],char:"\u{1f916}",fitzpatrick_scale:!1,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:"\u{1f63a}",fitzpatrick_scale:!1,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:"\u{1f638}",fitzpatrick_scale:!1,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:"\u{1f639}",fitzpatrick_scale:!1,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:"\u{1f63b}",fitzpatrick_scale:!1,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:"\u{1f63c}",fitzpatrick_scale:!1,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:"\u{1f63d}",fitzpatrick_scale:!1,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:"\u{1f640}",fitzpatrick_scale:!1,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:"\u{1f63f}",fitzpatrick_scale:!1,category:"people"},pouting_cat:{keywords:["animal","cats"],char:"\u{1f63e}",fitzpatrick_scale:!1,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:"\u{1f932}",fitzpatrick_scale:!0,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:"\u{1f64c}",fitzpatrick_scale:!0,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:"\u{1f44f}",fitzpatrick_scale:!0,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:"\u{1f44b}",fitzpatrick_scale:!0,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:"\u{1f919}",fitzpatrick_scale:!0,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:"\u{1f44d}",fitzpatrick_scale:!0,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:"\u{1f44e}",fitzpatrick_scale:!0,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:"\u{1f44a}",fitzpatrick_scale:!0,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:"\u270a",fitzpatrick_scale:!0,category:"people"},fist_left:{keywords:["hand","fistbump"],char:"\u{1f91b}",fitzpatrick_scale:!0,category:"people"},fist_right:{keywords:["hand","fistbump"],char:"\u{1f91c}",fitzpatrick_scale:!0,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:"\u270c",fitzpatrick_scale:!0,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:"\u{1f44c}",fitzpatrick_scale:!0,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:"\u270b",fitzpatrick_scale:!0,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:"\u{1f91a}",fitzpatrick_scale:!0,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:"\u{1f450}",fitzpatrick_scale:!0,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:"\u{1f4aa}",fitzpatrick_scale:!0,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:"\u{1f64f}",fitzpatrick_scale:!0,category:"people"},foot:{keywords:["kick","stomp"],char:"\u{1f9b6}",fitzpatrick_scale:!0,category:"people"},leg:{keywords:["kick","limb"],char:"\u{1f9b5}",fitzpatrick_scale:!0,category:"people"},handshake:{keywords:["agreement","shake"],char:"\u{1f91d}",fitzpatrick_scale:!1,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:"\u261d",fitzpatrick_scale:!0,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:"\u{1f446}",fitzpatrick_scale:!0,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:"\u{1f447}",fitzpatrick_scale:!0,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:"\u{1f448}",fitzpatrick_scale:!0,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:"\u{1f449}",fitzpatrick_scale:!0,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:"\u{1f595}",fitzpatrick_scale:!0,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:"\u{1f590}",fitzpatrick_scale:!0,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:"\u{1f91f}",fitzpatrick_scale:!0,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:"\u{1f918}",fitzpatrick_scale:!0,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:"\u{1f91e}",fitzpatrick_scale:!0,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:"\u{1f596}",fitzpatrick_scale:!0,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:"\u270d",fitzpatrick_scale:!0,category:"people"},selfie:{keywords:["camera","phone"],char:"\u{1f933}",fitzpatrick_scale:!0,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:"\u{1f485}",fitzpatrick_scale:!0,category:"people"},lips:{keywords:["mouth","kiss"],char:"\u{1f444}",fitzpatrick_scale:!1,category:"people"},tooth:{keywords:["teeth","dentist"],char:"\u{1f9b7}",fitzpatrick_scale:!1,category:"people"},tongue:{keywords:["mouth","playful"],char:"\u{1f445}",fitzpatrick_scale:!1,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:"\u{1f442}",fitzpatrick_scale:!0,category:"people"},nose:{keywords:["smell","sniff"],char:"\u{1f443}",fitzpatrick_scale:!0,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:"\u{1f441}",fitzpatrick_scale:!1,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:"\u{1f440}",fitzpatrick_scale:!1,category:"people"},brain:{keywords:["smart","intelligent"],char:"\u{1f9e0}",fitzpatrick_scale:!1,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:"\u{1f464}",fitzpatrick_scale:!1,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:"\u{1f465}",fitzpatrick_scale:!1,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:"\u{1f5e3}",fitzpatrick_scale:!1,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:"\u{1f476}",fitzpatrick_scale:!0,category:"people"},child:{keywords:["gender-neutral","young"],char:"\u{1f9d2}",fitzpatrick_scale:!0,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:"\u{1f466}",fitzpatrick_scale:!0,category:"people"},girl:{keywords:["female","woman","teenager"],char:"\u{1f467}",fitzpatrick_scale:!0,category:"people"},adult:{keywords:["gender-neutral","person"],char:"\u{1f9d1}",fitzpatrick_scale:!0,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:"\u{1f468}",fitzpatrick_scale:!0,category:"people"},woman:{keywords:["female","girls","lady"],char:"\u{1f469}",fitzpatrick_scale:!0,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:"\u{1f471}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:"\u{1f471}",fitzpatrick_scale:!0,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:"\u{1f9d4}",fitzpatrick_scale:!0,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:"\u{1f9d3}",fitzpatrick_scale:!0,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:"\u{1f474}",fitzpatrick_scale:!0,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:"\u{1f475}",fitzpatrick_scale:!0,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:"\u{1f472}",fitzpatrick_scale:!0,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:"\u{1f9d5}",fitzpatrick_scale:!0,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:"\u{1f473}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:"\u{1f473}",fitzpatrick_scale:!0,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:"\u{1f46e}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:"\u{1f46e}",fitzpatrick_scale:!0,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:"\u{1f477}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:"\u{1f477}",fitzpatrick_scale:!0,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:"\u{1f482}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:"\u{1f482}",fitzpatrick_scale:!0,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:"\u{1f575}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},male_detective:{keywords:["human","spy","detective"],char:"\u{1f575}",fitzpatrick_scale:!0,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:"\u{1f469}\u200d\u2695\ufe0f",fitzpatrick_scale:!0,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:"\u{1f468}\u200d\u2695\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:"\u{1f469}\u200d\u{1f33e}",fitzpatrick_scale:!0,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:"\u{1f468}\u200d\u{1f33e}",fitzpatrick_scale:!0,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:"\u{1f469}\u200d\u{1f373}",fitzpatrick_scale:!0,category:"people"},man_cook:{keywords:["chef","man","human"],char:"\u{1f468}\u200d\u{1f373}",fitzpatrick_scale:!0,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:"\u{1f469}\u200d\u{1f393}",fitzpatrick_scale:!0,category:"people"},man_student:{keywords:["graduate","man","human"],char:"\u{1f468}\u200d\u{1f393}",fitzpatrick_scale:!0,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:"\u{1f469}\u200d\u{1f3a4}",fitzpatrick_scale:!0,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:"\u{1f468}\u200d\u{1f3a4}",fitzpatrick_scale:!0,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:"\u{1f469}\u200d\u{1f3eb}",fitzpatrick_scale:!0,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:"\u{1f468}\u200d\u{1f3eb}",fitzpatrick_scale:!0,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:"\u{1f469}\u200d\u{1f3ed}",fitzpatrick_scale:!0,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:"\u{1f468}\u200d\u{1f3ed}",fitzpatrick_scale:!0,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:"\u{1f469}\u200d\u{1f4bb}",fitzpatrick_scale:!0,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:"\u{1f468}\u200d\u{1f4bb}",fitzpatrick_scale:!0,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:"\u{1f469}\u200d\u{1f4bc}",fitzpatrick_scale:!0,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:"\u{1f468}\u200d\u{1f4bc}",fitzpatrick_scale:!0,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:"\u{1f469}\u200d\u{1f527}",fitzpatrick_scale:!0,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:"\u{1f468}\u200d\u{1f527}",fitzpatrick_scale:!0,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:"\u{1f469}\u200d\u{1f52c}",fitzpatrick_scale:!0,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:"\u{1f468}\u200d\u{1f52c}",fitzpatrick_scale:!0,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:"\u{1f469}\u200d\u{1f3a8}",fitzpatrick_scale:!0,category:"people"},man_artist:{keywords:["painter","man","human"],char:"\u{1f468}\u200d\u{1f3a8}",fitzpatrick_scale:!0,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:"\u{1f469}\u200d\u{1f692}",fitzpatrick_scale:!0,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:"\u{1f468}\u200d\u{1f692}",fitzpatrick_scale:!0,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:"\u{1f469}\u200d\u2708\ufe0f",fitzpatrick_scale:!0,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:"\u{1f468}\u200d\u2708\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:"\u{1f469}\u200d\u{1f680}",fitzpatrick_scale:!0,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:"\u{1f468}\u200d\u{1f680}",fitzpatrick_scale:!0,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:"\u{1f469}\u200d\u2696\ufe0f",fitzpatrick_scale:!0,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:"\u{1f468}\u200d\u2696\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:"\u{1f9b8}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:"\u{1f9b8}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:"\u{1f9b9}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:"\u{1f9b9}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:"\u{1f936}",fitzpatrick_scale:!0,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:"\u{1f385}",fitzpatrick_scale:!0,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:"\u{1f9d9}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:"\u{1f9d9}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_elf:{keywords:["woman","female"],char:"\u{1f9dd}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_elf:{keywords:["man","male"],char:"\u{1f9dd}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_vampire:{keywords:["woman","female"],char:"\u{1f9db}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:"\u{1f9db}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:"\u{1f9df}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:"\u{1f9df}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},woman_genie:{keywords:["woman","female"],char:"\u{1f9de}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"people"},man_genie:{keywords:["man","male"],char:"\u{1f9de}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:"\u{1f9dc}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},merman:{keywords:["man","male","triton"],char:"\u{1f9dc}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_fairy:{keywords:["woman","female"],char:"\u{1f9da}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_fairy:{keywords:["man","male"],char:"\u{1f9da}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},angel:{keywords:["heaven","wings","halo"],char:"\u{1f47c}",fitzpatrick_scale:!0,category:"people"},pregnant_woman:{keywords:["baby"],char:"\u{1f930}",fitzpatrick_scale:!0,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:"\u{1f931}",fitzpatrick_scale:!0,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:"\u{1f478}",fitzpatrick_scale:!0,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:"\u{1f934}",fitzpatrick_scale:!0,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:"\u{1f470}",fitzpatrick_scale:!0,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:"\u{1f935}",fitzpatrick_scale:!0,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:"\u{1f3c3}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:"\u{1f3c3}",fitzpatrick_scale:!0,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:"\u{1f6b6}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},walking_man:{keywords:["human","feet","steps"],char:"\u{1f6b6}",fitzpatrick_scale:!0,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:"\u{1f483}",fitzpatrick_scale:!0,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:"\u{1f57a}",fitzpatrick_scale:!0,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:"\u{1f46f}",fitzpatrick_scale:!1,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:"\u{1f46f}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:"\u{1f46b}",fitzpatrick_scale:!1,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:"\u{1f46c}",fitzpatrick_scale:!1,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:"\u{1f46d}",fitzpatrick_scale:!1,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:"\u{1f647}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},bowing_man:{keywords:["man","male","boy"],char:"\u{1f647}",fitzpatrick_scale:!0,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:"\u{1f926}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:"\u{1f926}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:"\u{1f937}",fitzpatrick_scale:!0,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:"\u{1f937}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:"\u{1f481}",fitzpatrick_scale:!0,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:"\u{1f481}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:"\u{1f645}",fitzpatrick_scale:!0,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:"\u{1f645}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:"\u{1f646}",fitzpatrick_scale:!0,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:"\u{1f646}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:"\u{1f64b}",fitzpatrick_scale:!0,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:"\u{1f64b}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:"\u{1f64e}",fitzpatrick_scale:!0,category:"people"},pouting_man:{keywords:["male","boy","man"],char:"\u{1f64e}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:"\u{1f64d}",fitzpatrick_scale:!0,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:"\u{1f64d}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:"\u{1f487}",fitzpatrick_scale:!0,category:"people"},haircut_man:{keywords:["male","boy","man"],char:"\u{1f487}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:"\u{1f486}",fitzpatrick_scale:!0,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:"\u{1f486}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:"\u{1f9d6}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:"\u{1f9d6}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f491}",fitzpatrick_scale:!1,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f469}",fitzpatrick_scale:!1,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f468}",fitzpatrick_scale:!1,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f48f}",fitzpatrick_scale:!1,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f469}",fitzpatrick_scale:!1,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f468}",fitzpatrick_scale:!1,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:"\u{1f46a}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:"\u{1f469}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:"\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:"\u{1f468}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:"\u{1f468}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:"\u{1f9f6}",fitzpatrick_scale:!1,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:"\u{1f9f5}",fitzpatrick_scale:!1,category:"people"},coat:{keywords:["jacket"],char:"\u{1f9e5}",fitzpatrick_scale:!1,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:"\u{1f97c}",fitzpatrick_scale:!1,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:"\u{1f45a}",fitzpatrick_scale:!1,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:"\u{1f455}",fitzpatrick_scale:!1,category:"people"},jeans:{keywords:["fashion","shopping"],char:"\u{1f456}",fitzpatrick_scale:!1,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:"\u{1f454}",fitzpatrick_scale:!1,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:"\u{1f457}",fitzpatrick_scale:!1,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:"\u{1f459}",fitzpatrick_scale:!1,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:"\u{1f458}",fitzpatrick_scale:!1,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:"\u{1f484}",fitzpatrick_scale:!1,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:"\u{1f48b}",fitzpatrick_scale:!1,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:"\u{1f463}",fitzpatrick_scale:!1,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:"\u{1f97f}",fitzpatrick_scale:!1,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:"\u{1f460}",fitzpatrick_scale:!1,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:"\u{1f461}",fitzpatrick_scale:!1,category:"people"},boot:{keywords:["shoes","fashion"],char:"\u{1f462}",fitzpatrick_scale:!1,category:"people"},mans_shoe:{keywords:["fashion","male"],char:"\u{1f45e}",fitzpatrick_scale:!1,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:"\u{1f45f}",fitzpatrick_scale:!1,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:"\u{1f97e}",fitzpatrick_scale:!1,category:"people"},socks:{keywords:["stockings","clothes"],char:"\u{1f9e6}",fitzpatrick_scale:!1,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:"\u{1f9e4}",fitzpatrick_scale:!1,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:"\u{1f9e3}",fitzpatrick_scale:!1,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:"\u{1f452}",fitzpatrick_scale:!1,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:"\u{1f3a9}",fitzpatrick_scale:!1,category:"people"},billed_hat:{keywords:["cap","baseball"],char:"\u{1f9e2}",fitzpatrick_scale:!1,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:"\u26d1",fitzpatrick_scale:!1,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:"\u{1f393}",fitzpatrick_scale:!1,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:"\u{1f451}",fitzpatrick_scale:!1,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:"\u{1f392}",fitzpatrick_scale:!1,category:"people"},luggage:{keywords:["packing","travel"],char:"\u{1f9f3}",fitzpatrick_scale:!1,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:"\u{1f45d}",fitzpatrick_scale:!1,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:"\u{1f45b}",fitzpatrick_scale:!1,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:"\u{1f45c}",fitzpatrick_scale:!1,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:"\u{1f4bc}",fitzpatrick_scale:!1,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:"\u{1f453}",fitzpatrick_scale:!1,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:"\u{1f576}",fitzpatrick_scale:!1,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:"\u{1f97d}",fitzpatrick_scale:!1,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:"\u{1f48d}",fitzpatrick_scale:!1,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:"\u{1f302}",fitzpatrick_scale:!1,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:"\u{1f436}",fitzpatrick_scale:!1,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:"\u{1f431}",fitzpatrick_scale:!1,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:"\u{1f42d}",fitzpatrick_scale:!1,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:"\u{1f439}",fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:"\u{1f430}",fitzpatrick_scale:!1,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:"\u{1f98a}",fitzpatrick_scale:!1,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:"\u{1f43b}",fitzpatrick_scale:!1,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:"\u{1f43c}",fitzpatrick_scale:!1,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:"\u{1f428}",fitzpatrick_scale:!1,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:"\u{1f42f}",fitzpatrick_scale:!1,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:"\u{1f981}",fitzpatrick_scale:!1,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:"\u{1f42e}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:"\u{1f437}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:"\u{1f43d}",fitzpatrick_scale:!1,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:"\u{1f438}",fitzpatrick_scale:!1,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:"\u{1f991}",fitzpatrick_scale:!1,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:"\u{1f419}",fitzpatrick_scale:!1,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:"\u{1f990}",fitzpatrick_scale:!1,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:"\u{1f435}",fitzpatrick_scale:!1,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:"\u{1f98d}",fitzpatrick_scale:!1,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:"\u{1f648}",fitzpatrick_scale:!1,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:"\u{1f649}",fitzpatrick_scale:!1,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:"\u{1f64a}",fitzpatrick_scale:!1,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:"\u{1f412}",fitzpatrick_scale:!1,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:"\u{1f414}",fitzpatrick_scale:!1,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:"\u{1f427}",fitzpatrick_scale:!1,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:"\u{1f426}",fitzpatrick_scale:!1,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:"\u{1f424}",fitzpatrick_scale:!1,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:"\u{1f423}",fitzpatrick_scale:!1,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:"\u{1f425}",fitzpatrick_scale:!1,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:"\u{1f986}",fitzpatrick_scale:!1,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:"\u{1f985}",fitzpatrick_scale:!1,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:"\u{1f989}",fitzpatrick_scale:!1,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:"\u{1f987}",fitzpatrick_scale:!1,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:"\u{1f43a}",fitzpatrick_scale:!1,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:"\u{1f417}",fitzpatrick_scale:!1,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:"\u{1f434}",fitzpatrick_scale:!1,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:"\u{1f984}",fitzpatrick_scale:!1,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:"\u{1f41d}",fitzpatrick_scale:!1,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:"\u{1f41b}",fitzpatrick_scale:!1,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:"\u{1f98b}",fitzpatrick_scale:!1,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:"\u{1f40c}",fitzpatrick_scale:!1,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:"\u{1f41e}",fitzpatrick_scale:!1,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:"\u{1f41c}",fitzpatrick_scale:!1,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:"\u{1f997}",fitzpatrick_scale:!1,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:"\u{1f577}",fitzpatrick_scale:!1,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:"\u{1f982}",fitzpatrick_scale:!1,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:"\u{1f980}",fitzpatrick_scale:!1,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:"\u{1f40d}",fitzpatrick_scale:!1,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:"\u{1f98e}",fitzpatrick_scale:!1,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:"\u{1f996}",fitzpatrick_scale:!1,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:"\u{1f995}",fitzpatrick_scale:!1,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:"\u{1f422}",fitzpatrick_scale:!1,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:"\u{1f420}",fitzpatrick_scale:!1,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:"\u{1f41f}",fitzpatrick_scale:!1,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:"\u{1f421}",fitzpatrick_scale:!1,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:"\u{1f42c}",fitzpatrick_scale:!1,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:"\u{1f988}",fitzpatrick_scale:!1,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:"\u{1f433}",fitzpatrick_scale:!1,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:"\u{1f40b}",fitzpatrick_scale:!1,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:"\u{1f40a}",fitzpatrick_scale:!1,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:"\u{1f406}",fitzpatrick_scale:!1,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:"\u{1f993}",fitzpatrick_scale:!1,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:"\u{1f405}",fitzpatrick_scale:!1,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:"\u{1f403}",fitzpatrick_scale:!1,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:"\u{1f402}",fitzpatrick_scale:!1,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:"\u{1f404}",fitzpatrick_scale:!1,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:"\u{1f98c}",fitzpatrick_scale:!1,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:"\u{1f42a}",fitzpatrick_scale:!1,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:"\u{1f42b}",fitzpatrick_scale:!1,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:"\u{1f992}",fitzpatrick_scale:!1,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:"\u{1f418}",fitzpatrick_scale:!1,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:"\u{1f98f}",fitzpatrick_scale:!1,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:"\u{1f410}",fitzpatrick_scale:!1,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:"\u{1f40f}",fitzpatrick_scale:!1,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:"\u{1f411}",fitzpatrick_scale:!1,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:"\u{1f40e}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:"\u{1f416}",fitzpatrick_scale:!1,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:"\u{1f400}",fitzpatrick_scale:!1,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:"\u{1f401}",fitzpatrick_scale:!1,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:"\u{1f413}",fitzpatrick_scale:!1,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:"\u{1f983}",fitzpatrick_scale:!1,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:"\u{1f54a}",fitzpatrick_scale:!1,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:"\u{1f415}",fitzpatrick_scale:!1,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:"\u{1f429}",fitzpatrick_scale:!1,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:"\u{1f408}",fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:"\u{1f407}",fitzpatrick_scale:!1,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:"\u{1f43f}",fitzpatrick_scale:!1,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:"\u{1f994}",fitzpatrick_scale:!1,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:"\u{1f99d}",fitzpatrick_scale:!1,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:"\u{1f999}",fitzpatrick_scale:!1,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:"\u{1f99b}",fitzpatrick_scale:!1,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:"\u{1f998}",fitzpatrick_scale:!1,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:"\u{1f9a1}",fitzpatrick_scale:!1,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:"\u{1f9a2}",fitzpatrick_scale:!1,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:"\u{1f99a}",fitzpatrick_scale:!1,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:"\u{1f99c}",fitzpatrick_scale:!1,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:"\u{1f99e}",fitzpatrick_scale:!1,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:"\u{1f99f}",fitzpatrick_scale:!1,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:"\u{1f43e}",fitzpatrick_scale:!1,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:"\u{1f409}",fitzpatrick_scale:!1,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:"\u{1f432}",fitzpatrick_scale:!1,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:"\u{1f335}",fitzpatrick_scale:!1,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:"\u{1f384}",fitzpatrick_scale:!1,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:"\u{1f332}",fitzpatrick_scale:!1,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:"\u{1f333}",fitzpatrick_scale:!1,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:"\u{1f334}",fitzpatrick_scale:!1,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:"\u{1f331}",fitzpatrick_scale:!1,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:"\u{1f33f}",fitzpatrick_scale:!1,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:"\u2618",fitzpatrick_scale:!1,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:"\u{1f340}",fitzpatrick_scale:!1,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:"\u{1f38d}",fitzpatrick_scale:!1,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:"\u{1f38b}",fitzpatrick_scale:!1,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:"\u{1f343}",fitzpatrick_scale:!1,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:"\u{1f342}",fitzpatrick_scale:!1,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:"\u{1f341}",fitzpatrick_scale:!1,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:"\u{1f33e}",fitzpatrick_scale:!1,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:"\u{1f33a}",fitzpatrick_scale:!1,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:"\u{1f33b}",fitzpatrick_scale:!1,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:"\u{1f339}",fitzpatrick_scale:!1,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:"\u{1f940}",fitzpatrick_scale:!1,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:"\u{1f337}",fitzpatrick_scale:!1,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:"\u{1f33c}",fitzpatrick_scale:!1,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:"\u{1f338}",fitzpatrick_scale:!1,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:"\u{1f490}",fitzpatrick_scale:!1,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:"\u{1f344}",fitzpatrick_scale:!1,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:"\u{1f330}",fitzpatrick_scale:!1,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:"\u{1f383}",fitzpatrick_scale:!1,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:"\u{1f41a}",fitzpatrick_scale:!1,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:"\u{1f578}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:"\u{1f30e}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:"\u{1f30d}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:"\u{1f30f}",fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:"\u{1f315}",fitzpatrick_scale:!1,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:"\u{1f316}",fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f317}",fitzpatrick_scale:!1,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f318}",fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f311}",fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f312}",fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f313}",fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:"\u{1f314}",fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31a}",fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31d}",fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31b}",fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31c}",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:"\u{1f31e}",fitzpatrick_scale:!1,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:"\u{1f319}",fitzpatrick_scale:!1,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:"\u2b50",fitzpatrick_scale:!1,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:"\u{1f31f}",fitzpatrick_scale:!1,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:"\u{1f4ab}",fitzpatrick_scale:!1,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:"\u2728",fitzpatrick_scale:!1,category:"animals_and_nature"},comet:{keywords:["space"],char:"\u2604",fitzpatrick_scale:!1,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:"\u2600\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:"\u{1f324}",fitzpatrick_scale:!1,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:"\u26c5",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:"\u{1f325}",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:"\u{1f326}",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:"\u2601\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:"\u{1f327}",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:"\u26c8",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:"\u{1f329}",fitzpatrick_scale:!1,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:"\u26a1",fitzpatrick_scale:!1,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:"\u{1f525}",fitzpatrick_scale:!1,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:"\u{1f4a5}",fitzpatrick_scale:!1,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:"\u2744\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:"\u{1f328}",fitzpatrick_scale:!1,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:"\u26c4",fitzpatrick_scale:!1,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:"\u2603",fitzpatrick_scale:!1,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:"\u{1f32c}",fitzpatrick_scale:!1,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:"\u{1f4a8}",fitzpatrick_scale:!1,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:"\u{1f32a}",fitzpatrick_scale:!1,category:"animals_and_nature"},fog:{keywords:["weather"],char:"\u{1f32b}",fitzpatrick_scale:!1,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:"\u2602",fitzpatrick_scale:!1,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:"\u2614",fitzpatrick_scale:!1,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:"\u{1f4a7}",fitzpatrick_scale:!1,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:"\u{1f4a6}",fitzpatrick_scale:!1,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:"\u{1f30a}",fitzpatrick_scale:!1,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:"\u{1f34f}",fitzpatrick_scale:!1,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:"\u{1f34e}",fitzpatrick_scale:!1,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:"\u{1f350}",fitzpatrick_scale:!1,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:"\u{1f34a}",fitzpatrick_scale:!1,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:"\u{1f34b}",fitzpatrick_scale:!1,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:"\u{1f34c}",fitzpatrick_scale:!1,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:"\u{1f349}",fitzpatrick_scale:!1,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:"\u{1f347}",fitzpatrick_scale:!1,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:"\u{1f353}",fitzpatrick_scale:!1,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:"\u{1f348}",fitzpatrick_scale:!1,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:"\u{1f352}",fitzpatrick_scale:!1,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:"\u{1f351}",fitzpatrick_scale:!1,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:"\u{1f34d}",fitzpatrick_scale:!1,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:"\u{1f965}",fitzpatrick_scale:!1,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:"\u{1f95d}",fitzpatrick_scale:!1,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:"\u{1f96d}",fitzpatrick_scale:!1,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:"\u{1f951}",fitzpatrick_scale:!1,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:"\u{1f966}",fitzpatrick_scale:!1,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:"\u{1f345}",fitzpatrick_scale:!1,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:"\u{1f346}",fitzpatrick_scale:!1,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:"\u{1f952}",fitzpatrick_scale:!1,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:"\u{1f955}",fitzpatrick_scale:!1,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:"\u{1f336}",fitzpatrick_scale:!1,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:"\u{1f954}",fitzpatrick_scale:!1,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:"\u{1f33d}",fitzpatrick_scale:!1,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:"\u{1f96c}",fitzpatrick_scale:!1,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:"\u{1f360}",fitzpatrick_scale:!1,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:"\u{1f95c}",fitzpatrick_scale:!1,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:"\u{1f36f}",fitzpatrick_scale:!1,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:"\u{1f950}",fitzpatrick_scale:!1,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:"\u{1f35e}",fitzpatrick_scale:!1,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:"\u{1f956}",fitzpatrick_scale:!1,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:"\u{1f96f}",fitzpatrick_scale:!1,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:"\u{1f968}",fitzpatrick_scale:!1,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:"\u{1f9c0}",fitzpatrick_scale:!1,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:"\u{1f95a}",fitzpatrick_scale:!1,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:"\u{1f953}",fitzpatrick_scale:!1,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:"\u{1f969}",fitzpatrick_scale:!1,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:"\u{1f95e}",fitzpatrick_scale:!1,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:"\u{1f357}",fitzpatrick_scale:!1,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:"\u{1f356}",fitzpatrick_scale:!1,category:"food_and_drink"},bone:{keywords:["skeleton"],char:"\u{1f9b4}",fitzpatrick_scale:!1,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:"\u{1f364}",fitzpatrick_scale:!1,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:"\u{1f373}",fitzpatrick_scale:!1,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:"\u{1f354}",fitzpatrick_scale:!1,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:"\u{1f35f}",fitzpatrick_scale:!1,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:"\u{1f959}",fitzpatrick_scale:!1,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:"\u{1f32d}",fitzpatrick_scale:!1,category:"food_and_drink"},pizza:{keywords:["food","party"],char:"\u{1f355}",fitzpatrick_scale:!1,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:"\u{1f96a}",fitzpatrick_scale:!1,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:"\u{1f96b}",fitzpatrick_scale:!1,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:"\u{1f35d}",fitzpatrick_scale:!1,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:"\u{1f32e}",fitzpatrick_scale:!1,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:"\u{1f32f}",fitzpatrick_scale:!1,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:"\u{1f957}",fitzpatrick_scale:!1,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:"\u{1f958}",fitzpatrick_scale:!1,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:"\u{1f35c}",fitzpatrick_scale:!1,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:"\u{1f372}",fitzpatrick_scale:!1,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:"\u{1f365}",fitzpatrick_scale:!1,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:"\u{1f960}",fitzpatrick_scale:!1,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:"\u{1f363}",fitzpatrick_scale:!1,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:"\u{1f371}",fitzpatrick_scale:!1,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:"\u{1f35b}",fitzpatrick_scale:!1,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:"\u{1f359}",fitzpatrick_scale:!1,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:"\u{1f35a}",fitzpatrick_scale:!1,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:"\u{1f358}",fitzpatrick_scale:!1,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:"\u{1f362}",fitzpatrick_scale:!1,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:"\u{1f361}",fitzpatrick_scale:!1,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:"\u{1f367}",fitzpatrick_scale:!1,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:"\u{1f368}",fitzpatrick_scale:!1,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:"\u{1f366}",fitzpatrick_scale:!1,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:"\u{1f967}",fitzpatrick_scale:!1,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:"\u{1f370}",fitzpatrick_scale:!1,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:"\u{1f9c1}",fitzpatrick_scale:!1,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:"\u{1f96e}",fitzpatrick_scale:!1,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:"\u{1f382}",fitzpatrick_scale:!1,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:"\u{1f36e}",fitzpatrick_scale:!1,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:"\u{1f36c}",fitzpatrick_scale:!1,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:"\u{1f36d}",fitzpatrick_scale:!1,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:"\u{1f36b}",fitzpatrick_scale:!1,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:"\u{1f37f}",fitzpatrick_scale:!1,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:"\u{1f95f}",fitzpatrick_scale:!1,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:"\u{1f369}",fitzpatrick_scale:!1,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:"\u{1f36a}",fitzpatrick_scale:!1,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:"\u{1f95b}",fitzpatrick_scale:!1,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"\u{1f37a}",fitzpatrick_scale:!1,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"\u{1f37b}",fitzpatrick_scale:!1,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:"\u{1f942}",fitzpatrick_scale:!1,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:"\u{1f377}",fitzpatrick_scale:!1,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:"\u{1f943}",fitzpatrick_scale:!1,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:"\u{1f378}",fitzpatrick_scale:!1,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:"\u{1f379}",fitzpatrick_scale:!1,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:"\u{1f37e}",fitzpatrick_scale:!1,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:"\u{1f376}",fitzpatrick_scale:!1,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:"\u{1f375}",fitzpatrick_scale:!1,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:"\u{1f964}",fitzpatrick_scale:!1,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:"\u2615",fitzpatrick_scale:!1,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:"\u{1f37c}",fitzpatrick_scale:!1,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:"\u{1f9c2}",fitzpatrick_scale:!1,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:"\u{1f944}",fitzpatrick_scale:!1,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:"\u{1f374}",fitzpatrick_scale:!1,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:"\u{1f37d}",fitzpatrick_scale:!1,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:"\u{1f963}",fitzpatrick_scale:!1,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:"\u{1f961}",fitzpatrick_scale:!1,category:"food_and_drink"},chopsticks:{keywords:["food"],char:"\u{1f962}",fitzpatrick_scale:!1,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:"\u26bd",fitzpatrick_scale:!1,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:"\u{1f3c0}",fitzpatrick_scale:!1,category:"activity"},football:{keywords:["sports","balls","NFL"],char:"\u{1f3c8}",fitzpatrick_scale:!1,category:"activity"},baseball:{keywords:["sports","balls"],char:"\u26be",fitzpatrick_scale:!1,category:"activity"},softball:{keywords:["sports","balls"],char:"\u{1f94e}",fitzpatrick_scale:!1,category:"activity"},tennis:{keywords:["sports","balls","green"],char:"\u{1f3be}",fitzpatrick_scale:!1,category:"activity"},volleyball:{keywords:["sports","balls"],char:"\u{1f3d0}",fitzpatrick_scale:!1,category:"activity"},rugby_football:{keywords:["sports","team"],char:"\u{1f3c9}",fitzpatrick_scale:!1,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:"\u{1f94f}",fitzpatrick_scale:!1,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:"\u{1f3b1}",fitzpatrick_scale:!1,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:"\u26f3",fitzpatrick_scale:!1,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:"\u{1f3cc}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"activity"},golfing_man:{keywords:["sports","business"],char:"\u{1f3cc}",fitzpatrick_scale:!0,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:"\u{1f3d3}",fitzpatrick_scale:!1,category:"activity"},badminton:{keywords:["sports"],char:"\u{1f3f8}",fitzpatrick_scale:!1,category:"activity"},goal_net:{keywords:["sports"],char:"\u{1f945}",fitzpatrick_scale:!1,category:"activity"},ice_hockey:{keywords:["sports"],char:"\u{1f3d2}",fitzpatrick_scale:!1,category:"activity"},field_hockey:{keywords:["sports"],char:"\u{1f3d1}",fitzpatrick_scale:!1,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:"\u{1f94d}",fitzpatrick_scale:!1,category:"activity"},cricket:{keywords:["sports"],char:"\u{1f3cf}",fitzpatrick_scale:!1,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:"\u{1f3bf}",fitzpatrick_scale:!1,category:"activity"},skier:{keywords:["sports","winter","snow"],char:"\u26f7",fitzpatrick_scale:!1,category:"activity"},snowboarder:{keywords:["sports","winter"],char:"\u{1f3c2}",fitzpatrick_scale:!0,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:"\u{1f93a}",fitzpatrick_scale:!1,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:"\u{1f93c}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:"\u{1f93c}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:"\u{1f938}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:"\u{1f938}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},woman_playing_handball:{keywords:["sports"],char:"\u{1f93e}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_playing_handball:{keywords:["sports"],char:"\u{1f93e}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},ice_skate:{keywords:["sports"],char:"\u26f8",fitzpatrick_scale:!1,category:"activity"},curling_stone:{keywords:["sports"],char:"\u{1f94c}",fitzpatrick_scale:!1,category:"activity"},skateboard:{keywords:["board"],char:"\u{1f6f9}",fitzpatrick_scale:!1,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:"\u{1f6f7}",fitzpatrick_scale:!1,category:"activity"},bow_and_arrow:{keywords:["sports"],char:"\u{1f3f9}",fitzpatrick_scale:!1,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:"\u{1f3a3}",fitzpatrick_scale:!1,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:"\u{1f94a}",fitzpatrick_scale:!1,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:"\u{1f94b}",fitzpatrick_scale:!1,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:"\u{1f6a3}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:"\u{1f6a3}",fitzpatrick_scale:!0,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:"\u{1f9d7}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:"\u{1f9d7}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:"\u{1f3ca}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:"\u{1f3ca}",fitzpatrick_scale:!0,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:"\u{1f93d}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:"\u{1f93d}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:"\u{1f9d8}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:"\u{1f9d8}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:"\u{1f3c4}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:"\u{1f3c4}",fitzpatrick_scale:!0,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:"\u{1f6c0}",fitzpatrick_scale:!0,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:"\u26f9\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},basketball_man:{keywords:["sports","human"],char:"\u26f9",fitzpatrick_scale:!0,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:"\u{1f3cb}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:"\u{1f3cb}",fitzpatrick_scale:!0,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:"\u{1f6b4}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:"\u{1f6b4}",fitzpatrick_scale:!0,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:"\u{1f6b5}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:"\u{1f6b5}",fitzpatrick_scale:!0,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:"\u{1f3c7}",fitzpatrick_scale:!0,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:"\u{1f574}",fitzpatrick_scale:!0,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:"\u{1f3c6}",fitzpatrick_scale:!1,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:"\u{1f3bd}",fitzpatrick_scale:!1,category:"activity"},medal_sports:{keywords:["award","winning"],char:"\u{1f3c5}",fitzpatrick_scale:!1,category:"activity"},medal_military:{keywords:["award","winning","army"],char:"\u{1f396}",fitzpatrick_scale:!1,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:"\u{1f947}",fitzpatrick_scale:!1,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:"\u{1f948}",fitzpatrick_scale:!1,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:"\u{1f949}",fitzpatrick_scale:!1,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:"\u{1f397}",fitzpatrick_scale:!1,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:"\u{1f3f5}",fitzpatrick_scale:!1,category:"activity"},ticket:{keywords:["event","concert","pass"],char:"\u{1f3ab}",fitzpatrick_scale:!1,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:"\u{1f39f}",fitzpatrick_scale:!1,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:"\u{1f3ad}",fitzpatrick_scale:!1,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:"\u{1f3a8}",fitzpatrick_scale:!1,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:"\u{1f3aa}",fitzpatrick_scale:!1,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:"\u{1f939}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:"\u{1f939}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:"\u{1f3a4}",fitzpatrick_scale:!1,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:"\u{1f3a7}",fitzpatrick_scale:!1,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:"\u{1f3bc}",fitzpatrick_scale:!1,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:"\u{1f3b9}",fitzpatrick_scale:!1,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:"\u{1f941}",fitzpatrick_scale:!1,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:"\u{1f3b7}",fitzpatrick_scale:!1,category:"activity"},trumpet:{keywords:["music","brass"],char:"\u{1f3ba}",fitzpatrick_scale:!1,category:"activity"},guitar:{keywords:["music","instrument"],char:"\u{1f3b8}",fitzpatrick_scale:!1,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:"\u{1f3bb}",fitzpatrick_scale:!1,category:"activity"},clapper:{keywords:["movie","film","record"],char:"\u{1f3ac}",fitzpatrick_scale:!1,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:"\u{1f3ae}",fitzpatrick_scale:!1,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:"\u{1f47e}",fitzpatrick_scale:!1,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:"\u{1f3af}",fitzpatrick_scale:!1,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:"\u{1f3b2}",fitzpatrick_scale:!1,category:"activity"},chess_pawn:{keywords:["expendable"],char:"\u265f",fitzpatrick_scale:!1,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:"\u{1f3b0}",fitzpatrick_scale:!1,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:"\u{1f9e9}",fitzpatrick_scale:!1,category:"activity"},bowling:{keywords:["sports","fun","play"],char:"\u{1f3b3}",fitzpatrick_scale:!1,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:"\u{1f697}",fitzpatrick_scale:!1,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:"\u{1f695}",fitzpatrick_scale:!1,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:"\u{1f699}",fitzpatrick_scale:!1,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:"\u{1f68c}",fitzpatrick_scale:!1,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:"\u{1f68e}",fitzpatrick_scale:!1,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:"\u{1f3ce}",fitzpatrick_scale:!1,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:"\u{1f693}",fitzpatrick_scale:!1,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:"\u{1f691}",fitzpatrick_scale:!1,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:"\u{1f692}",fitzpatrick_scale:!1,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:"\u{1f690}",fitzpatrick_scale:!1,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:"\u{1f69a}",fitzpatrick_scale:!1,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:"\u{1f69b}",fitzpatrick_scale:!1,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:"\u{1f69c}",fitzpatrick_scale:!1,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:"\u{1f6f4}",fitzpatrick_scale:!1,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:"\u{1f3cd}",fitzpatrick_scale:!1,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:"\u{1f6b2}",fitzpatrick_scale:!1,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:"\u{1f6f5}",fitzpatrick_scale:!1,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:"\u{1f6a8}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:"\u{1f694}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:"\u{1f68d}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:"\u{1f698}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:"\u{1f696}",fitzpatrick_scale:!1,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:"\u{1f6a1}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:"\u{1f6a0}",fitzpatrick_scale:!1,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:"\u{1f69f}",fitzpatrick_scale:!1,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:"\u{1f683}",fitzpatrick_scale:!1,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:"\u{1f68b}",fitzpatrick_scale:!1,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:"\u{1f69d}",fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:"\u{1f684}",fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:"\u{1f685}",fitzpatrick_scale:!1,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:"\u{1f688}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:"\u{1f69e}",fitzpatrick_scale:!1,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:"\u{1f682}",fitzpatrick_scale:!1,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:"\u{1f686}",fitzpatrick_scale:!1,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:"\u{1f687}",fitzpatrick_scale:!1,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:"\u{1f68a}",fitzpatrick_scale:!1,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:"\u{1f689}",fitzpatrick_scale:!1,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:"\u{1f6f8}",fitzpatrick_scale:!1,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:"\u{1f681}",fitzpatrick_scale:!1,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:"\u{1f6e9}",fitzpatrick_scale:!1,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:"\u2708\ufe0f",fitzpatrick_scale:!1,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:"\u{1f6eb}",fitzpatrick_scale:!1,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:"\u{1f6ec}",fitzpatrick_scale:!1,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:"\u26f5",fitzpatrick_scale:!1,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:"\u{1f6e5}",fitzpatrick_scale:!1,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:"\u{1f6a4}",fitzpatrick_scale:!1,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:"\u26f4",fitzpatrick_scale:!1,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:"\u{1f6f3}",fitzpatrick_scale:!1,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:"\u{1f680}",fitzpatrick_scale:!1,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:"\u{1f6f0}",fitzpatrick_scale:!1,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:"\u{1f4ba}",fitzpatrick_scale:!1,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:"\u{1f6f6}",fitzpatrick_scale:!1,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:"\u2693",fitzpatrick_scale:!1,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:"\u{1f6a7}",fitzpatrick_scale:!1,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:"\u26fd",fitzpatrick_scale:!1,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:"\u{1f68f}",fitzpatrick_scale:!1,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:"\u{1f6a6}",fitzpatrick_scale:!1,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:"\u{1f6a5}",fitzpatrick_scale:!1,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:"\u{1f3c1}",fitzpatrick_scale:!1,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:"\u{1f6a2}",fitzpatrick_scale:!1,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:"\u{1f3a1}",fitzpatrick_scale:!1,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:"\u{1f3a2}",fitzpatrick_scale:!1,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:"\u{1f3a0}",fitzpatrick_scale:!1,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:"\u{1f3d7}",fitzpatrick_scale:!1,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:"\u{1f301}",fitzpatrick_scale:!1,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:"\u{1f5fc}",fitzpatrick_scale:!1,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:"\u{1f3ed}",fitzpatrick_scale:!1,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:"\u26f2",fitzpatrick_scale:!1,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:"\u{1f391}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:"\u26f0",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:"\u{1f3d4}",fitzpatrick_scale:!1,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:"\u{1f5fb}",fitzpatrick_scale:!1,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:"\u{1f30b}",fitzpatrick_scale:!1,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:"\u{1f5fe}",fitzpatrick_scale:!1,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:"\u{1f3d5}",fitzpatrick_scale:!1,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:"\u26fa",fitzpatrick_scale:!1,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:"\u{1f3de}",fitzpatrick_scale:!1,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:"\u{1f6e3}",fitzpatrick_scale:!1,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:"\u{1f6e4}",fitzpatrick_scale:!1,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:"\u{1f305}",fitzpatrick_scale:!1,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:"\u{1f304}",fitzpatrick_scale:!1,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:"\u{1f3dc}",fitzpatrick_scale:!1,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:"\u{1f3d6}",fitzpatrick_scale:!1,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:"\u{1f3dd}",fitzpatrick_scale:!1,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:"\u{1f307}",fitzpatrick_scale:!1,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:"\u{1f306}",fitzpatrick_scale:!1,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:"\u{1f3d9}",fitzpatrick_scale:!1,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:"\u{1f303}",fitzpatrick_scale:!1,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:"\u{1f309}",fitzpatrick_scale:!1,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:"\u{1f30c}",fitzpatrick_scale:!1,category:"travel_and_places"},stars:{keywords:["night","photo"],char:"\u{1f320}",fitzpatrick_scale:!1,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:"\u{1f387}",fitzpatrick_scale:!1,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:"\u{1f386}",fitzpatrick_scale:!1,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:"\u{1f308}",fitzpatrick_scale:!1,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:"\u{1f3d8}",fitzpatrick_scale:!1,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:"\u{1f3f0}",fitzpatrick_scale:!1,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:"\u{1f3ef}",fitzpatrick_scale:!1,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:"\u{1f3df}",fitzpatrick_scale:!1,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:"\u{1f5fd}",fitzpatrick_scale:!1,category:"travel_and_places"},house:{keywords:["building","home"],char:"\u{1f3e0}",fitzpatrick_scale:!1,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:"\u{1f3e1}",fitzpatrick_scale:!1,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:"\u{1f3da}",fitzpatrick_scale:!1,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:"\u{1f3e2}",fitzpatrick_scale:!1,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:"\u{1f3ec}",fitzpatrick_scale:!1,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:"\u{1f3e3}",fitzpatrick_scale:!1,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:"\u{1f3e4}",fitzpatrick_scale:!1,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:"\u{1f3e5}",fitzpatrick_scale:!1,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:"\u{1f3e6}",fitzpatrick_scale:!1,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:"\u{1f3e8}",fitzpatrick_scale:!1,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:"\u{1f3ea}",fitzpatrick_scale:!1,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:"\u{1f3eb}",fitzpatrick_scale:!1,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:"\u{1f3e9}",fitzpatrick_scale:!1,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:"\u{1f492}",fitzpatrick_scale:!1,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:"\u{1f3db}",fitzpatrick_scale:!1,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:"\u26ea",fitzpatrick_scale:!1,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:"\u{1f54c}",fitzpatrick_scale:!1,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:"\u{1f54d}",fitzpatrick_scale:!1,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:"\u{1f54b}",fitzpatrick_scale:!1,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:"\u26e9",fitzpatrick_scale:!1,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:"\u231a",fitzpatrick_scale:!1,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:"\u{1f4f1}",fitzpatrick_scale:!1,category:"objects"},calling:{keywords:["iphone","incoming"],char:"\u{1f4f2}",fitzpatrick_scale:!1,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:"\u{1f4bb}",fitzpatrick_scale:!1,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:"\u2328",fitzpatrick_scale:!1,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:"\u{1f5a5}",fitzpatrick_scale:!1,category:"objects"},printer:{keywords:["paper","ink"],char:"\u{1f5a8}",fitzpatrick_scale:!1,category:"objects"},computer_mouse:{keywords:["click"],char:"\u{1f5b1}",fitzpatrick_scale:!1,category:"objects"},trackball:{keywords:["technology","trackpad"],char:"\u{1f5b2}",fitzpatrick_scale:!1,category:"objects"},joystick:{keywords:["game","play"],char:"\u{1f579}",fitzpatrick_scale:!1,category:"objects"},clamp:{keywords:["tool"],char:"\u{1f5dc}",fitzpatrick_scale:!1,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:"\u{1f4bd}",fitzpatrick_scale:!1,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:"\u{1f4be}",fitzpatrick_scale:!1,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:"\u{1f4bf}",fitzpatrick_scale:!1,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:"\u{1f4c0}",fitzpatrick_scale:!1,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:"\u{1f4fc}",fitzpatrick_scale:!1,category:"objects"},camera:{keywords:["gadgets","photography"],char:"\u{1f4f7}",fitzpatrick_scale:!1,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:"\u{1f4f8}",fitzpatrick_scale:!1,category:"objects"},video_camera:{keywords:["film","record"],char:"\u{1f4f9}",fitzpatrick_scale:!1,category:"objects"},movie_camera:{keywords:["film","record"],char:"\u{1f3a5}",fitzpatrick_scale:!1,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:"\u{1f4fd}",fitzpatrick_scale:!1,category:"objects"},film_strip:{keywords:["movie"],char:"\u{1f39e}",fitzpatrick_scale:!1,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:"\u{1f4de}",fitzpatrick_scale:!1,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:"\u260e\ufe0f",fitzpatrick_scale:!1,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:"\u{1f4df}",fitzpatrick_scale:!1,category:"objects"},fax:{keywords:["communication","technology"],char:"\u{1f4e0}",fitzpatrick_scale:!1,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:"\u{1f4fa}",fitzpatrick_scale:!1,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:"\u{1f4fb}",fitzpatrick_scale:!1,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:"\u{1f399}",fitzpatrick_scale:!1,category:"objects"},level_slider:{keywords:["scale"],char:"\u{1f39a}",fitzpatrick_scale:!1,category:"objects"},control_knobs:{keywords:["dial"],char:"\u{1f39b}",fitzpatrick_scale:!1,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:"\u{1f9ed}",fitzpatrick_scale:!1,category:"objects"},stopwatch:{keywords:["time","deadline"],char:"\u23f1",fitzpatrick_scale:!1,category:"objects"},timer_clock:{keywords:["alarm"],char:"\u23f2",fitzpatrick_scale:!1,category:"objects"},alarm_clock:{keywords:["time","wake"],char:"\u23f0",fitzpatrick_scale:!1,category:"objects"},mantelpiece_clock:{keywords:["time"],char:"\u{1f570}",fitzpatrick_scale:!1,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:"\u23f3",fitzpatrick_scale:!1,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:"\u231b",fitzpatrick_scale:!1,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:"\u{1f4e1}",fitzpatrick_scale:!1,category:"objects"},battery:{keywords:["power","energy","sustain"],char:"\u{1f50b}",fitzpatrick_scale:!1,category:"objects"},electric_plug:{keywords:["charger","power"],char:"\u{1f50c}",fitzpatrick_scale:!1,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:"\u{1f4a1}",fitzpatrick_scale:!1,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:"\u{1f526}",fitzpatrick_scale:!1,category:"objects"},candle:{keywords:["fire","wax"],char:"\u{1f56f}",fitzpatrick_scale:!1,category:"objects"},fire_extinguisher:{keywords:["quench"],char:"\u{1f9ef}",fitzpatrick_scale:!1,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:"\u{1f5d1}",fitzpatrick_scale:!1,category:"objects"},oil_drum:{keywords:["barrell"],char:"\u{1f6e2}",fitzpatrick_scale:!1,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:"\u{1f4b8}",fitzpatrick_scale:!1,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:"\u{1f4b5}",fitzpatrick_scale:!1,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:"\u{1f4b4}",fitzpatrick_scale:!1,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:"\u{1f4b6}",fitzpatrick_scale:!1,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:"\u{1f4b7}",fitzpatrick_scale:!1,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:"\u{1f4b0}",fitzpatrick_scale:!1,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:"\u{1f4b3}",fitzpatrick_scale:!1,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:"\u{1f48e}",fitzpatrick_scale:!1,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:"\u2696",fitzpatrick_scale:!1,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:"\u{1f9f0}",fitzpatrick_scale:!1,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:"\u{1f527}",fitzpatrick_scale:!1,category:"objects"},hammer:{keywords:["tools","build","create"],char:"\u{1f528}",fitzpatrick_scale:!1,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:"\u2692",fitzpatrick_scale:!1,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:"\u{1f6e0}",fitzpatrick_scale:!1,category:"objects"},pick:{keywords:["tools","dig"],char:"\u26cf",fitzpatrick_scale:!1,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:"\u{1f529}",fitzpatrick_scale:!1,category:"objects"},gear:{keywords:["cog"],char:"\u2699",fitzpatrick_scale:!1,category:"objects"},brick:{keywords:["bricks"],char:"\u{1f9f1}",fitzpatrick_scale:!1,category:"objects"},chains:{keywords:["lock","arrest"],char:"\u26d3",fitzpatrick_scale:!1,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:"\u{1f9f2}",fitzpatrick_scale:!1,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:"\u{1f52b}",fitzpatrick_scale:!1,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:"\u{1f4a3}",fitzpatrick_scale:!1,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:"\u{1f9e8}",fitzpatrick_scale:!1,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:"\u{1f52a}",fitzpatrick_scale:!1,category:"objects"},dagger:{keywords:["weapon"],char:"\u{1f5e1}",fitzpatrick_scale:!1,category:"objects"},crossed_swords:{keywords:["weapon"],char:"\u2694",fitzpatrick_scale:!1,category:"objects"},shield:{keywords:["protection","security"],char:"\u{1f6e1}",fitzpatrick_scale:!1,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:"\u{1f6ac}",fitzpatrick_scale:!1,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:"\u2620",fitzpatrick_scale:!1,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:"\u26b0",fitzpatrick_scale:!1,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:"\u26b1",fitzpatrick_scale:!1,category:"objects"},amphora:{keywords:["vase","jar"],char:"\u{1f3fa}",fitzpatrick_scale:!1,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:"\u{1f52e}",fitzpatrick_scale:!1,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:"\u{1f4ff}",fitzpatrick_scale:!1,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:"\u{1f9ff}",fitzpatrick_scale:!1,category:"objects"},barber:{keywords:["hair","salon","style"],char:"\u{1f488}",fitzpatrick_scale:!1,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:"\u2697",fitzpatrick_scale:!1,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:"\u{1f52d}",fitzpatrick_scale:!1,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:"\u{1f52c}",fitzpatrick_scale:!1,category:"objects"},hole:{keywords:["embarrassing"],char:"\u{1f573}",fitzpatrick_scale:!1,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:"\u{1f48a}",fitzpatrick_scale:!1,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:"\u{1f489}",fitzpatrick_scale:!1,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:"\u{1f9ec}",fitzpatrick_scale:!1,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:"\u{1f9a0}",fitzpatrick_scale:!1,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:"\u{1f9eb}",fitzpatrick_scale:!1,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:"\u{1f9ea}",fitzpatrick_scale:!1,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:"\u{1f321}",fitzpatrick_scale:!1,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:"\u{1f9f9}",fitzpatrick_scale:!1,category:"objects"},basket:{keywords:["laundry"],char:"\u{1f9fa}",fitzpatrick_scale:!1,category:"objects"},toilet_paper:{keywords:["roll"],char:"\u{1f9fb}",fitzpatrick_scale:!1,category:"objects"},label:{keywords:["sale","tag"],char:"\u{1f3f7}",fitzpatrick_scale:!1,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:"\u{1f516}",fitzpatrick_scale:!1,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:"\u{1f6bd}",fitzpatrick_scale:!1,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:"\u{1f6bf}",fitzpatrick_scale:!1,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:"\u{1f6c1}",fitzpatrick_scale:!1,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:"\u{1f9fc}",fitzpatrick_scale:!1,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:"\u{1f9fd}",fitzpatrick_scale:!1,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:"\u{1f9f4}",fitzpatrick_scale:!1,category:"objects"},key:{keywords:["lock","door","password"],char:"\u{1f511}",fitzpatrick_scale:!1,category:"objects"},old_key:{keywords:["lock","door","password"],char:"\u{1f5dd}",fitzpatrick_scale:!1,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:"\u{1f6cb}",fitzpatrick_scale:!1,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:"\u{1f6cc}",fitzpatrick_scale:!0,category:"objects"},bed:{keywords:["sleep","rest"],char:"\u{1f6cf}",fitzpatrick_scale:!1,category:"objects"},door:{keywords:["house","entry","exit"],char:"\u{1f6aa}",fitzpatrick_scale:!1,category:"objects"},bellhop_bell:{keywords:["service"],char:"\u{1f6ce}",fitzpatrick_scale:!1,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:"\u{1f9f8}",fitzpatrick_scale:!1,category:"objects"},framed_picture:{keywords:["photography"],char:"\u{1f5bc}",fitzpatrick_scale:!1,category:"objects"},world_map:{keywords:["location","direction"],char:"\u{1f5fa}",fitzpatrick_scale:!1,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:"\u26f1",fitzpatrick_scale:!1,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:"\u{1f5ff}",fitzpatrick_scale:!1,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:"\u{1f6cd}",fitzpatrick_scale:!1,category:"objects"},shopping_cart:{keywords:["trolley"],char:"\u{1f6d2}",fitzpatrick_scale:!1,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:"\u{1f388}",fitzpatrick_scale:!1,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:"\u{1f38f}",fitzpatrick_scale:!1,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:"\u{1f380}",fitzpatrick_scale:!1,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:"\u{1f381}",fitzpatrick_scale:!1,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:"\u{1f38a}",fitzpatrick_scale:!1,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:"\u{1f389}",fitzpatrick_scale:!1,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:"\u{1f38e}",fitzpatrick_scale:!1,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:"\u{1f390}",fitzpatrick_scale:!1,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:"\u{1f38c}",fitzpatrick_scale:!1,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:"\u{1f3ee}",fitzpatrick_scale:!1,category:"objects"},red_envelope:{keywords:["gift"],char:"\u{1f9e7}",fitzpatrick_scale:!1,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:"\u2709\ufe0f",fitzpatrick_scale:!1,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:"\u{1f4e9}",fitzpatrick_scale:!1,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:"\u{1f4e8}",fitzpatrick_scale:!1,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:"\u{1f4e7}",fitzpatrick_scale:!1,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:"\u{1f48c}",fitzpatrick_scale:!1,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:"\u{1f4ee}",fitzpatrick_scale:!1,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:"\u{1f4ea}",fitzpatrick_scale:!1,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:"\u{1f4eb}",fitzpatrick_scale:!1,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:"\u{1f4ec}",fitzpatrick_scale:!1,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:"\u{1f4ed}",fitzpatrick_scale:!1,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:"\u{1f4e6}",fitzpatrick_scale:!1,category:"objects"},postal_horn:{keywords:["instrument","music"],char:"\u{1f4ef}",fitzpatrick_scale:!1,category:"objects"},inbox_tray:{keywords:["email","documents"],char:"\u{1f4e5}",fitzpatrick_scale:!1,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:"\u{1f4e4}",fitzpatrick_scale:!1,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:"\u{1f4dc}",fitzpatrick_scale:!1,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:"\u{1f4c3}",fitzpatrick_scale:!1,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:"\u{1f4d1}",fitzpatrick_scale:!1,category:"objects"},receipt:{keywords:["accounting","expenses"],char:"\u{1f9fe}",fitzpatrick_scale:!1,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:"\u{1f4ca}",fitzpatrick_scale:!1,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:"\u{1f4c8}",fitzpatrick_scale:!1,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:"\u{1f4c9}",fitzpatrick_scale:!1,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:"\u{1f4c4}",fitzpatrick_scale:!1,category:"objects"},date:{keywords:["calendar","schedule"],char:"\u{1f4c5}",fitzpatrick_scale:!1,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:"\u{1f4c6}",fitzpatrick_scale:!1,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:"\u{1f5d3}",fitzpatrick_scale:!1,category:"objects"},card_index:{keywords:["business","stationery"],char:"\u{1f4c7}",fitzpatrick_scale:!1,category:"objects"},card_file_box:{keywords:["business","stationery"],char:"\u{1f5c3}",fitzpatrick_scale:!1,category:"objects"},ballot_box:{keywords:["election","vote"],char:"\u{1f5f3}",fitzpatrick_scale:!1,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:"\u{1f5c4}",fitzpatrick_scale:!1,category:"objects"},clipboard:{keywords:["stationery","documents"],char:"\u{1f4cb}",fitzpatrick_scale:!1,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:"\u{1f5d2}",fitzpatrick_scale:!1,category:"objects"},file_folder:{keywords:["documents","business","office"],char:"\u{1f4c1}",fitzpatrick_scale:!1,category:"objects"},open_file_folder:{keywords:["documents","load"],char:"\u{1f4c2}",fitzpatrick_scale:!1,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:"\u{1f5c2}",fitzpatrick_scale:!1,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:"\u{1f5de}",fitzpatrick_scale:!1,category:"objects"},newspaper:{keywords:["press","headline"],char:"\u{1f4f0}",fitzpatrick_scale:!1,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:"\u{1f4d3}",fitzpatrick_scale:!1,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:"\u{1f4d5}",fitzpatrick_scale:!1,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:"\u{1f4d7}",fitzpatrick_scale:!1,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:"\u{1f4d8}",fitzpatrick_scale:!1,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:"\u{1f4d9}",fitzpatrick_scale:!1,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:"\u{1f4d4}",fitzpatrick_scale:!1,category:"objects"},ledger:{keywords:["notes","paper"],char:"\u{1f4d2}",fitzpatrick_scale:!1,category:"objects"},books:{keywords:["literature","library","study"],char:"\u{1f4da}",fitzpatrick_scale:!1,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:"\u{1f4d6}",fitzpatrick_scale:!1,category:"objects"},safety_pin:{keywords:["diaper"],char:"\u{1f9f7}",fitzpatrick_scale:!1,category:"objects"},link:{keywords:["rings","url"],char:"\u{1f517}",fitzpatrick_scale:!1,category:"objects"},paperclip:{keywords:["documents","stationery"],char:"\u{1f4ce}",fitzpatrick_scale:!1,category:"objects"},paperclips:{keywords:["documents","stationery"],char:"\u{1f587}",fitzpatrick_scale:!1,category:"objects"},scissors:{keywords:["stationery","cut"],char:"\u2702\ufe0f",fitzpatrick_scale:!1,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:"\u{1f4d0}",fitzpatrick_scale:!1,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:"\u{1f4cf}",fitzpatrick_scale:!1,category:"objects"},abacus:{keywords:["calculation"],char:"\u{1f9ee}",fitzpatrick_scale:!1,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:"\u{1f4cc}",fitzpatrick_scale:!1,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:"\u{1f4cd}",fitzpatrick_scale:!1,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:"\u{1f6a9}",fitzpatrick_scale:!1,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:"\u{1f3f3}",fitzpatrick_scale:!1,category:"objects"},black_flag:{keywords:["pirate"],char:"\u{1f3f4}",fitzpatrick_scale:!1,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:"\u{1f3f3}\ufe0f\u200d\u{1f308}",fitzpatrick_scale:!1,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:"\u{1f510}",fitzpatrick_scale:!1,category:"objects"},lock:{keywords:["security","password","padlock"],char:"\u{1f512}",fitzpatrick_scale:!1,category:"objects"},unlock:{keywords:["privacy","security"],char:"\u{1f513}",fitzpatrick_scale:!1,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:"\u{1f50f}",fitzpatrick_scale:!1,category:"objects"},pen:{keywords:["stationery","writing","write"],char:"\u{1f58a}",fitzpatrick_scale:!1,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:"\u{1f58b}",fitzpatrick_scale:!1,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:"\u2712\ufe0f",fitzpatrick_scale:!1,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:"\u{1f4dd}",fitzpatrick_scale:!1,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:"\u270f\ufe0f",fitzpatrick_scale:!1,category:"objects"},crayon:{keywords:["drawing","creativity"],char:"\u{1f58d}",fitzpatrick_scale:!1,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:"\u{1f58c}",fitzpatrick_scale:!1,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:"\u{1f50d}",fitzpatrick_scale:!1,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:"\u{1f50e}",fitzpatrick_scale:!1,category:"objects"},heart:{keywords:["love","like","valentines"],char:"\u2764\ufe0f",fitzpatrick_scale:!1,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f9e1}",fitzpatrick_scale:!1,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49b}",fitzpatrick_scale:!1,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49a}",fitzpatrick_scale:!1,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f499}",fitzpatrick_scale:!1,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49c}",fitzpatrick_scale:!1,category:"symbols"},black_heart:{keywords:["evil"],char:"\u{1f5a4}",fitzpatrick_scale:!1,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:"\u{1f494}",fitzpatrick_scale:!1,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:"\u2763",fitzpatrick_scale:!1,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:"\u{1f495}",fitzpatrick_scale:!1,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:"\u{1f49e}",fitzpatrick_scale:!1,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:"\u{1f493}",fitzpatrick_scale:!1,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:"\u{1f497}",fitzpatrick_scale:!1,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f496}",fitzpatrick_scale:!1,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:"\u{1f498}",fitzpatrick_scale:!1,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:"\u{1f49d}",fitzpatrick_scale:!1,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:"\u{1f49f}",fitzpatrick_scale:!1,category:"symbols"},peace_symbol:{keywords:["hippie"],char:"\u262e",fitzpatrick_scale:!1,category:"symbols"},latin_cross:{keywords:["christianity"],char:"\u271d",fitzpatrick_scale:!1,category:"symbols"},star_and_crescent:{keywords:["islam"],char:"\u262a",fitzpatrick_scale:!1,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"\u{1f549}",fitzpatrick_scale:!1,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"\u2638",fitzpatrick_scale:!1,category:"symbols"},star_of_david:{keywords:["judaism"],char:"\u2721",fitzpatrick_scale:!1,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:"\u{1f52f}",fitzpatrick_scale:!1,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:"\u{1f54e}",fitzpatrick_scale:!1,category:"symbols"},yin_yang:{keywords:["balance"],char:"\u262f",fitzpatrick_scale:!1,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:"\u2626",fitzpatrick_scale:!1,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:"\u{1f6d0}",fitzpatrick_scale:!1,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:"\u26ce",fitzpatrick_scale:!1,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u2648",fitzpatrick_scale:!1,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:"\u2649",fitzpatrick_scale:!1,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264a",fitzpatrick_scale:!1,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264b",fitzpatrick_scale:!1,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u264c",fitzpatrick_scale:!1,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264d",fitzpatrick_scale:!1,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u264e",fitzpatrick_scale:!1,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:"\u264f",fitzpatrick_scale:!1,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u2650",fitzpatrick_scale:!1,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u2651",fitzpatrick_scale:!1,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u2652",fitzpatrick_scale:!1,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:"\u2653",fitzpatrick_scale:!1,category:"symbols"},id:{keywords:["purple-square","words"],char:"\u{1f194}",fitzpatrick_scale:!1,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:"\u269b",fitzpatrick_scale:!1,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:"\u{1f233}",fitzpatrick_scale:!1,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:"\u{1f239}",fitzpatrick_scale:!1,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:"\u2622",fitzpatrick_scale:!1,category:"symbols"},biohazard:{keywords:["danger"],char:"\u2623",fitzpatrick_scale:!1,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:"\u{1f4f4}",fitzpatrick_scale:!1,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:"\u{1f4f3}",fitzpatrick_scale:!1,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:"\u{1f236}",fitzpatrick_scale:!1,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:"\u{1f21a}",fitzpatrick_scale:!1,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:"\u{1f238}",fitzpatrick_scale:!1,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:"\u{1f23a}",fitzpatrick_scale:!1,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:"\u{1f237}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:"\u2734\ufe0f",fitzpatrick_scale:!1,category:"symbols"},vs:{keywords:["words","orange-square"],char:"\u{1f19a}",fitzpatrick_scale:!1,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:"\u{1f251}",fitzpatrick_scale:!1,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:"\u{1f4ae}",fitzpatrick_scale:!1,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:"\u{1f250}",fitzpatrick_scale:!1,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:"\u3299\ufe0f",fitzpatrick_scale:!1,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:"\u3297\ufe0f",fitzpatrick_scale:!1,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:"\u{1f234}",fitzpatrick_scale:!1,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:"\u{1f235}",fitzpatrick_scale:!1,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:"\u{1f232}",fitzpatrick_scale:!1,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:"\u{1f170}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:"\u{1f171}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:"\u{1f18e}",fitzpatrick_scale:!1,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:"\u{1f191}",fitzpatrick_scale:!1,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:"\u{1f17e}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:"\u{1f198}",fitzpatrick_scale:!1,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:"\u26d4",fitzpatrick_scale:!1,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:"\u{1f4db}",fitzpatrick_scale:!1,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:"\u{1f6ab}",fitzpatrick_scale:!1,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:"\u274c",fitzpatrick_scale:!1,category:"symbols"},o:{keywords:["circle","round"],char:"\u2b55",fitzpatrick_scale:!1,category:"symbols"},stop_sign:{keywords:["stop"],char:"\u{1f6d1}",fitzpatrick_scale:!1,category:"symbols"},anger:{keywords:["angry","mad"],char:"\u{1f4a2}",fitzpatrick_scale:!1,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:"\u2668\ufe0f",fitzpatrick_scale:!1,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:"\u{1f6b7}",fitzpatrick_scale:!1,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:"\u{1f6af}",fitzpatrick_scale:!1,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:"\u{1f6b3}",fitzpatrick_scale:!1,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:"\u{1f6b1}",fitzpatrick_scale:!1,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:"\u{1f51e}",fitzpatrick_scale:!1,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:"\u{1f4f5}",fitzpatrick_scale:!1,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:"\u2757",fitzpatrick_scale:!1,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:"\u2755",fitzpatrick_scale:!1,category:"symbols"},question:{keywords:["doubt","confused"],char:"\u2753",fitzpatrick_scale:!1,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:"\u2754",fitzpatrick_scale:!1,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:"\u203c\ufe0f",fitzpatrick_scale:!1,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:"\u2049\ufe0f",fitzpatrick_scale:!1,category:"symbols"},100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:"\u{1f4af}",fitzpatrick_scale:!1,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:"\u{1f505}",fitzpatrick_scale:!1,category:"symbols"},high_brightness:{keywords:["sun","light"],char:"\u{1f506}",fitzpatrick_scale:!1,category:"symbols"},trident:{keywords:["weapon","spear"],char:"\u{1f531}",fitzpatrick_scale:!1,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:"\u269c",fitzpatrick_scale:!1,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:"\u303d\ufe0f",fitzpatrick_scale:!1,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:"\u26a0\ufe0f",fitzpatrick_scale:!1,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:"\u{1f6b8}",fitzpatrick_scale:!1,category:"symbols"},beginner:{keywords:["badge","shield"],char:"\u{1f530}",fitzpatrick_scale:!1,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:"\u267b\ufe0f",fitzpatrick_scale:!1,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:"\u{1f22f}",fitzpatrick_scale:!1,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:"\u{1f4b9}",fitzpatrick_scale:!1,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:"\u2747\ufe0f",fitzpatrick_scale:!1,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:"\u2733\ufe0f",fitzpatrick_scale:!1,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:"\u274e",fitzpatrick_scale:!1,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:"\u2705",fitzpatrick_scale:!1,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:"\u{1f4a0}",fitzpatrick_scale:!1,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:"\u{1f300}",fitzpatrick_scale:!1,category:"symbols"},loop:{keywords:["tape","cassette"],char:"\u27bf",fitzpatrick_scale:!1,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:"\u{1f310}",fitzpatrick_scale:!1,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:"\u24c2\ufe0f",fitzpatrick_scale:!1,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:"\u{1f3e7}",fitzpatrick_scale:!1,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:"\u{1f202}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:"\u{1f6c2}",fitzpatrick_scale:!1,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:"\u{1f6c3}",fitzpatrick_scale:!1,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:"\u{1f6c4}",fitzpatrick_scale:!1,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:"\u{1f6c5}",fitzpatrick_scale:!1,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:"\u267f",fitzpatrick_scale:!1,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:"\u{1f6ad}",fitzpatrick_scale:!1,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:"\u{1f6be}",fitzpatrick_scale:!1,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:"\u{1f17f}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:"\u{1f6b0}",fitzpatrick_scale:!1,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:"\u{1f6b9}",fitzpatrick_scale:!1,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:"\u{1f6ba}",fitzpatrick_scale:!1,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:"\u{1f6bc}",fitzpatrick_scale:!1,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:"\u{1f6bb}",fitzpatrick_scale:!1,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:"\u{1f6ae}",fitzpatrick_scale:!1,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:"\u{1f3a6}",fitzpatrick_scale:!1,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:"\u{1f4f6}",fitzpatrick_scale:!1,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:"\u{1f201}",fitzpatrick_scale:!1,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:"\u{1f196}",fitzpatrick_scale:!1,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:"\u{1f197}",fitzpatrick_scale:!1,category:"symbols"},up:{keywords:["blue-square","above","high"],char:"\u{1f199}",fitzpatrick_scale:!1,category:"symbols"},cool:{keywords:["words","blue-square"],char:"\u{1f192}",fitzpatrick_scale:!1,category:"symbols"},new:{keywords:["blue-square","words","start"],char:"\u{1f195}",fitzpatrick_scale:!1,category:"symbols"},free:{keywords:["blue-square","words"],char:"\u{1f193}",fitzpatrick_scale:!1,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:"0\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:"1\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:"2\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:"3\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:"4\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:"5\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:"6\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:"7\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:"8\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:"9\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:"\u{1f51f}",fitzpatrick_scale:!1,category:"symbols"},asterisk:{keywords:["star","keycap"],char:"*\u20e3",fitzpatrick_scale:!1,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:"\u{1f522}",fitzpatrick_scale:!1,category:"symbols"},eject_button:{keywords:["blue-square"],char:"\u23cf\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:"\u25b6\ufe0f",fitzpatrick_scale:!1,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:"\u23f8",fitzpatrick_scale:!1,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:"\u23ed",fitzpatrick_scale:!1,category:"symbols"},stop_button:{keywords:["blue-square"],char:"\u23f9",fitzpatrick_scale:!1,category:"symbols"},record_button:{keywords:["blue-square"],char:"\u23fa",fitzpatrick_scale:!1,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:"\u23ef",fitzpatrick_scale:!1,category:"symbols"},previous_track_button:{keywords:["backward"],char:"\u23ee",fitzpatrick_scale:!1,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:"\u23e9",fitzpatrick_scale:!1,category:"symbols"},rewind:{keywords:["play","blue-square"],char:"\u23ea",fitzpatrick_scale:!1,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:"\u{1f500}",fitzpatrick_scale:!1,category:"symbols"},repeat:{keywords:["loop","record"],char:"\u{1f501}",fitzpatrick_scale:!1,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:"\u{1f502}",fitzpatrick_scale:!1,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:"\u25c0\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:"\u{1f53c}",fitzpatrick_scale:!1,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:"\u{1f53d}",fitzpatrick_scale:!1,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:"\u23eb",fitzpatrick_scale:!1,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:"\u23ec",fitzpatrick_scale:!1,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:"\u27a1\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:"\u2b05\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:"\u2b06\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:"\u2b07\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:"\u2197\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:"\u2198\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:"\u2199\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:"\u2196\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:"\u2195\ufe0f",fitzpatrick_scale:!1,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:"\u2194\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:"\u{1f504}",fitzpatrick_scale:!1,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:"\u21aa\ufe0f",fitzpatrick_scale:!1,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:"\u21a9\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:"\u2934\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:"\u2935\ufe0f",fitzpatrick_scale:!1,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:"#\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:"\u2139\ufe0f",fitzpatrick_scale:!1,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:"\u{1f524}",fitzpatrick_scale:!1,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:"\u{1f521}",fitzpatrick_scale:!1,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:"\u{1f520}",fitzpatrick_scale:!1,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:"\u{1f523}",fitzpatrick_scale:!1,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:"\u{1f3b5}",fitzpatrick_scale:!1,category:"symbols"},notes:{keywords:["music","score"],char:"\u{1f3b6}",fitzpatrick_scale:!1,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:"\u3030\ufe0f",fitzpatrick_scale:!1,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:"\u27b0",fitzpatrick_scale:!1,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:"\u2714\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:"\u{1f503}",fitzpatrick_scale:!1,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:"\u2795",fitzpatrick_scale:!1,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:"\u2796",fitzpatrick_scale:!1,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:"\u2797",fitzpatrick_scale:!1,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:"\u2716\ufe0f",fitzpatrick_scale:!1,category:"symbols"},infinity:{keywords:["forever"],char:"\u267e",fitzpatrick_scale:!1,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:"\u{1f4b2}",fitzpatrick_scale:!1,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:"\u{1f4b1}",fitzpatrick_scale:!1,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:"\xa9\ufe0f",fitzpatrick_scale:!1,category:"symbols"},registered:{keywords:["alphabet","circle"],char:"\xae\ufe0f",fitzpatrick_scale:!1,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:"\u2122\ufe0f",fitzpatrick_scale:!1,category:"symbols"},end:{keywords:["words","arrow"],char:"\u{1f51a}",fitzpatrick_scale:!1,category:"symbols"},back:{keywords:["arrow","words","return"],char:"\u{1f519}",fitzpatrick_scale:!1,category:"symbols"},on:{keywords:["arrow","words"],char:"\u{1f51b}",fitzpatrick_scale:!1,category:"symbols"},top:{keywords:["words","blue-square"],char:"\u{1f51d}",fitzpatrick_scale:!1,category:"symbols"},soon:{keywords:["arrow","words"],char:"\u{1f51c}",fitzpatrick_scale:!1,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:"\u2611\ufe0f",fitzpatrick_scale:!1,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:"\u{1f518}",fitzpatrick_scale:!1,category:"symbols"},white_circle:{keywords:["shape","round"],char:"\u26aa",fitzpatrick_scale:!1,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:"\u26ab",fitzpatrick_scale:!1,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:"\u{1f534}",fitzpatrick_scale:!1,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:"\u{1f535}",fitzpatrick_scale:!1,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f538}",fitzpatrick_scale:!1,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f539}",fitzpatrick_scale:!1,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f536}",fitzpatrick_scale:!1,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f537}",fitzpatrick_scale:!1,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:"\u{1f53a}",fitzpatrick_scale:!1,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:"\u25aa\ufe0f",fitzpatrick_scale:!1,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:"\u25ab\ufe0f",fitzpatrick_scale:!1,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:"\u2b1b",fitzpatrick_scale:!1,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:"\u2b1c",fitzpatrick_scale:!1,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:"\u{1f53b}",fitzpatrick_scale:!1,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:"\u25fc\ufe0f",fitzpatrick_scale:!1,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:"\u25fb\ufe0f",fitzpatrick_scale:!1,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:"\u25fe",fitzpatrick_scale:!1,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:"\u25fd",fitzpatrick_scale:!1,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:"\u{1f532}",fitzpatrick_scale:!1,category:"symbols"},white_square_button:{keywords:["shape","input"],char:"\u{1f533}",fitzpatrick_scale:!1,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:"\u{1f508}",fitzpatrick_scale:!1,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:"\u{1f509}",fitzpatrick_scale:!1,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:"\u{1f50a}",fitzpatrick_scale:!1,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:"\u{1f507}",fitzpatrick_scale:!1,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:"\u{1f4e3}",fitzpatrick_scale:!1,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:"\u{1f4e2}",fitzpatrick_scale:!1,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:"\u{1f514}",fitzpatrick_scale:!1,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:"\u{1f515}",fitzpatrick_scale:!1,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:"\u{1f0cf}",fitzpatrick_scale:!1,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:"\u{1f004}",fitzpatrick_scale:!1,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:"\u2660\ufe0f",fitzpatrick_scale:!1,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:"\u2663\ufe0f",fitzpatrick_scale:!1,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:"\u2665\ufe0f",fitzpatrick_scale:!1,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:"\u2666\ufe0f",fitzpatrick_scale:!1,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:"\u{1f3b4}",fitzpatrick_scale:!1,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:"\u{1f4ad}",fitzpatrick_scale:!1,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:"\u{1f5ef}",fitzpatrick_scale:!1,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:"\u{1f4ac}",fitzpatrick_scale:!1,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:"\u{1f5e8}",fitzpatrick_scale:!1,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:"\u{1f550}",fitzpatrick_scale:!1,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:"\u{1f551}",fitzpatrick_scale:!1,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:"\u{1f552}",fitzpatrick_scale:!1,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:"\u{1f553}",fitzpatrick_scale:!1,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:"\u{1f554}",fitzpatrick_scale:!1,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:"\u{1f555}",fitzpatrick_scale:!1,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:"\u{1f556}",fitzpatrick_scale:!1,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:"\u{1f557}",fitzpatrick_scale:!1,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:"\u{1f558}",fitzpatrick_scale:!1,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:"\u{1f559}",fitzpatrick_scale:!1,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:"\u{1f55a}",fitzpatrick_scale:!1,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:"\u{1f55b}",fitzpatrick_scale:!1,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:"\u{1f55c}",fitzpatrick_scale:!1,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:"\u{1f55d}",fitzpatrick_scale:!1,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:"\u{1f55e}",fitzpatrick_scale:!1,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:"\u{1f55f}",fitzpatrick_scale:!1,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:"\u{1f560}",fitzpatrick_scale:!1,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:"\u{1f561}",fitzpatrick_scale:!1,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:"\u{1f562}",fitzpatrick_scale:!1,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:"\u{1f563}",fitzpatrick_scale:!1,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:"\u{1f564}",fitzpatrick_scale:!1,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:"\u{1f565}",fitzpatrick_scale:!1,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:"\u{1f566}",fitzpatrick_scale:!1,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:"\u{1f567}",fitzpatrick_scale:!1,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},aland_islands:{keywords:["\xc5land","islands","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:"\u{1f1e8}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},curacao:{keywords:["cura\xe7ao","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:"\u{1f1ea}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:"\u{1f1eb}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:"\u{1f1e9}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:"\u{1f1ef}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:"\u{1f1fd}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:"\u{1f1fe}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:"\u{1f1f0}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:"\u{1f1f4}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:"\u{1f1f6}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},reunion:{keywords:["r\xe9union","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},st_barthelemy:{keywords:["saint","barth\xe9lemy","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:"\u{1f1fc}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:"\u{1f1f0}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:"\u{1f1ec}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},england:{keywords:["flag","english"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0065}\u{e006e}\u{e0067}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},scotland:{keywords:["flag","scottish"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0073}\u{e0063}\u{e0074}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},wales:{keywords:["flag","welsh"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0077}\u{e006c}\u{e0073}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:"\u{1f1fc}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:"\u{1f1fe}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:"\u{1f1fa}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:"\u{1f3f4}\u200d\u2620\ufe0f",fitzpatrick_scale:!1,category:"flags"}}); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/emoticons/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/plugin.min.js new file mode 100644 index 0000000..f705ce3 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/emoticons/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>t===e,o=e(null),n=e(void 0),s=()=>{},r=()=>!1;class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return null==t?a.none():a.some(t)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const i=(t,e)=>{const o=t.length,n=new Array(o);for(let s=0;s{let e=t;return{get:()=>e,set:t=>{e=t}}},c=Object.keys,u=Object.hasOwnProperty,g=(t,e)=>{const o=c(t);for(let n=0,s=o.length;nu.call(t,e),m=(h=(t,e)=>e,(...t)=>{if(0===t.length)throw new Error("Can't merge zero objects");const e={};for(let o=0;o{const t=(t=>{const e=l(a.none()),o=()=>e.get().each(t);return{clear:()=>{o(),e.set(a.none())},isSet:()=>e.get().isSome(),get:()=>e.get(),set:t=>{o(),e.set(a.some(t))}}})(s);return{...t,on:e=>t.get().each(e)}},y=(t,e,o=0,s)=>{const r=t.indexOf(e,o);return-1!==r&&(!!n(s)||r+e.length<=s)};var v=tinymce.util.Tools.resolve("tinymce.Resource");const f=t=>e=>e.options.get(t),b=f("emoticons_database"),w=f("emoticons_database_url"),j=f("emoticons_database_id"),C=f("emoticons_append"),_=f("emoticons_images_url"),A="All",k={symbols:"Symbols",people:"People",animals_and_nature:"Animals and Nature",food_and_drink:"Food and Drink",activity:"Activity",travel_and_places:"Travel and Places",objects:"Objects",flags:"Flags",user:"User Defined"},O=(t,e)=>d(t,e)?t[e]:e,x=t=>{const e=C(t);return o=t=>({keywords:[],category:"user",...t}),((t,e)=>{const o={};return g(t,((t,n)=>{const s=e(t,n);o[s.k]=s.v})),o})(e,((t,e)=>({k:e,v:o(t)})));var o},E=(t,e)=>y(t.title.toLowerCase(),e)||((t,o)=>{for(let o=0,s=t.length;o{const n=[],s=e.toLowerCase(),a=o.fold((()=>r),(t=>e=>e>=t));for(let o=0;o{const n={pattern:"",results:L(e.listAll(),"",a.some(300))},s=l(A),r=((t,e)=>{let n=null;const s=()=>{o(n)||(clearTimeout(n),n=null)};return{cancel:s,throttle:(...e)=>{s(),n=setTimeout((()=>{n=null,t.apply(null,e)}),200)}}})((t=>{(t=>{const o=t.getData(),n=s.get(),r=e.listCategory(n),i=L(r,o[S],n===A?a.some(300):a.none());t.setData({results:i})})(t)})),c={label:"Search",type:"input",name:S},u={type:"collection",name:"results"},g=()=>({title:"Emojis",size:"normal",body:{type:"tabpanel",tabs:i(e.listCategories(),(t=>({title:t,name:t,items:[c,u]})))},initialData:n,onTabChange:(t,e)=>{s.set(e.newTabName),r.throttle(t)},onChange:r.throttle,onAction:(e,o)=>{"results"===o.name&&(((t,e)=>{t.insertContent(e)})(t,o.value),e.close())},buttons:[{type:"cancel",text:"Close",primary:!0}]}),d=t.windowManager.open(g());d.focus(S),e.hasLoaded()||(d.block("Loading emojis..."),e.waitForLoad().then((()=>{d.redial(g()),r.throttle(d),d.focus(S),d.unblock()})).catch((t=>{d.redial({title:"Emojis",body:{type:"panel",items:[{type:"alertbanner",level:"error",icon:"warning",text:"Could not load emojis"}]},buttons:[{type:"cancel",text:"Close",primary:!0}],initialData:{pattern:"",results:[]}}),d.focus(S),d.unblock()})))},T=t=>e=>{const o=()=>{e.setEnabled(t.selection.isEditable())};return t.on("NodeChange",o),o(),()=>{t.off("NodeChange",o)}};t.add("emoticons",((t,e)=>{((t,e)=>{const o=t.options.register;o("emoticons_database",{processor:"string",default:"emojis"}),o("emoticons_database_url",{processor:"string",default:`${e}/js/${b(t)}${t.suffix}.js`}),o("emoticons_database_id",{processor:"string",default:"tinymce.plugins.emoticons"}),o("emoticons_append",{processor:"object",default:{}}),o("emoticons_images_url",{processor:"string",default:"https://cdnjs.cloudflare.com/ajax/libs/twemoji/15.1.0/72x72/"})})(t,e);const o=((t,e,o)=>{const n=p(),s=p(),r=_(t),i=t=>{return o="=4&&e.substr(0,4)===o?t.char.replace(/src="([^"]+)"/,((t,e)=>`src="${r}${e}"`)):t.char;var e,o};t.on("init",(()=>{v.load(o,e).then((e=>{const o=x(t);(t=>{const e={},o=[];g(t,((t,n)=>{const s={title:n,keywords:t.keywords,char:i(t),category:O(k,t.category)},r=void 0!==e[s.category]?e[s.category]:[];e[s.category]=r.concat([s]),o.push(s)})),n.set(e),s.set(o)})(m(e,o))}),(t=>{console.log(`Failed to load emojis: ${t}`),n.set({}),s.set([])}))}));const l=()=>s.get().getOr([]),u=()=>n.isSet()&&s.isSet();return{listCategories:()=>[A].concat(c(n.get().getOr({}))),hasLoaded:u,waitForLoad:()=>u()?Promise.resolve(!0):new Promise(((t,o)=>{let n=15;const s=setInterval((()=>{u()?(clearInterval(s),t(!0)):(n--,n<0&&(console.log("Could not load emojis from url: "+e),clearInterval(s),o(!1)))}),100)})),listAll:l,listCategory:t=>t===A?l():n.get().bind((e=>a.from(e[t]))).getOr([])}})(t,w(t),j(t));return((t,e)=>{t.addCommand("mceEmoticons",(()=>N(t,e)))})(t,o),(t=>{const e=()=>t.execCommand("mceEmoticons");t.ui.registry.addButton("emoticons",{tooltip:"Emojis",icon:"emoji",onAction:e,onSetup:T(t)}),t.ui.registry.addMenuItem("emoticons",{text:"Emojis...",icon:"emoji",onAction:e,onSetup:T(t)})})(t),((t,e)=>{t.ui.registry.addAutocompleter("emoticons",{trigger:":",columns:"auto",minChars:2,fetch:(t,o)=>e.waitForLoad().then((()=>{const n=e.listAll();return L(n,t,a.some(o))})),onAction:(e,o,n)=>{t.selection.setRng(o),t.insertContent(n),e.hide()}})})(t,o),(t=>{t.on("PreInit",(()=>{t.parser.addAttributeFilter("data-emoticon",(t=>{((t,e)=>{for(let e=0,n=t.length;eo.waitForLoad().then((()=>o.listAll()))}}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/fullscreen/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/fullscreen/plugin.min.js new file mode 100644 index 0000000..2fe33d2 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/fullscreen/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";const e=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}};var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,r=e=>t=>typeof t===e,o=e=>t=>e===t,s=n("string"),i=n("object"),l=n("array"),a=o(null),c=r("boolean"),u=o(void 0),d=e=>!(e=>null==e)(e),m=r("function"),h=r("number"),g=()=>{},p=e=>()=>e;function f(e,...t){return(...n)=>{const r=t.concat(n);return e.apply(null,r)}}const v=p(!1),w=p(!0);class y{constructor(e,t){this.tag=e,this.value=t}static some(e){return new y(!0,e)}static none(){return y.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?y.some(e(this.value)):y.none()}bind(e){return this.tag?e(this.value):y.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:y.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?y.some(e):y.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}y.singletonNone=new y(!1);const b=Array.prototype.push,S=(e,t)=>{const n=e.length,r=new Array(n);for(let o=0;o{for(let n=0,r=e.length;n{const n=[];for(let r=0,o=e.length;r((e,t,n)=>{for(let r=0,o=e.length;r{const n=e(y.none()),r=()=>n.get().each(t);return{clear:()=>{r(),n.set(y.none())},isSet:()=>n.get().isSome(),get:()=>n.get(),set:e=>{r(),n.set(y.some(e))}}},k=()=>O((e=>e.unbind())),T=Object.keys,C="undefined"!=typeof window?window:Function("return this;")(),A=(e,t)=>((e,t)=>{let n=null!=t?t:C;for(let t=0;t{const t=A("ownerDocument.defaultView",e);return i(e)&&((e=>((e,t)=>{const n=((e,t)=>A(e,t))(e,t);if(null==n)throw new Error(e+" not available on this browser");return n})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(R(e).constructor.name))},M=e=>t=>(e=>e.dom.nodeType)(t)===e,P=M(1),D=M(3),N=M(11),H=(e,t)=>{const n=e.dom.getAttribute(t);return null===n?void 0:n},V=(e,t)=>{e.dom.removeAttribute(t)},W=(e,t,n=0,r)=>{const o=e.indexOf(t,n);return-1!==o&&(!!u(r)||o+t.length<=r)},q=e=>void 0!==e.style&&m(e.style.getPropertyValue),B=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},I=B,j=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},_=e=>I(e.dom.ownerDocument),z=e=>S(e.dom.childNodes,I),K=e=>{const t=(e=>I(e.dom.getRootNode()))(e);return N(n=t)&&d(n.dom.host)?y.some(t):y.none();var n},$=e=>I(e.dom.host),U=e=>{const t=D(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return K(I(t)).fold((()=>n.body.contains(t)),(r=U,o=$,e=>r(o(e))));var r,o},X=(e,t,n)=>{if(!s(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);q(e)&&e.style.setProperty(t,n)},Y=(e,t,n)=>{const r=e.dom;X(r,t,n)},G=(e,t)=>{const n=e.dom;((e,t)=>{const n=T(e);for(let r=0,o=n.length;r{X(n,t,e)}))},J=(e,t)=>{const n=e.dom,r=window.getComputedStyle(n).getPropertyValue(t);return""!==r||U(e)?r:Q(n,t)},Q=(e,t)=>q(e)?e.style.getPropertyValue(t):"",Z=e=>{const t=I((e=>{if(d(e.target)){const t=I(e.target);if(P(t)&&d(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return((e,t)=>0e.stopPropagation(),r=()=>e.preventDefault(),o=(s=r,i=n,(...e)=>s(i.apply(null,e)));var s,i;return((e,t,n,r,o,s,i)=>({target:e,x:t,y:n,stop:r,prevent:o,kill:s,raw:i}))(t,e.clientX,e.clientY,n,r,o,e)},ee=(e,t,n,r)=>{e.dom.removeEventListener(t,n,r)},te=w,ne=(e,t,n)=>((e,t,n,r)=>((e,t,n,r,o)=>{const s=((e,t)=>n=>{e(n)&&t(Z(n))})(n,r);return e.dom.addEventListener(t,s,o),{unbind:f(ee,e,t,s,o)}})(e,t,n,r,!1))(e,t,te,n),re=()=>oe(0,0),oe=(e,t)=>({major:e,minor:t}),se={nu:oe,detect:(e,t)=>{const n=String(t).toLowerCase();return 0===e.length?re():((e,t)=>{const n=((e,t)=>{for(let n=0;nNumber(t.replace(n,"$"+e));return oe(r(1),r(2))})(e,n)},unknown:re},ie=(e,t)=>{const n=String(t).toLowerCase();return F(e,(e=>e.search(n)))},le=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,ae=e=>t=>W(t,e),ce=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>W(e,"edge/")&&W(e,"chrome")&&W(e,"safari")&&W(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,le],search:e=>W(e,"chrome")&&!W(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>W(e,"msie")||W(e,"trident")},{name:"Opera",versionRegexes:[le,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:ae("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:ae("firefox")},{name:"Safari",versionRegexes:[le,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(W(e,"safari")||W(e,"mobile/"))&&W(e,"applewebkit")}],ue=[{name:"Windows",search:ae("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>W(e,"iphone")||W(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:ae("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:ae("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:ae("linux"),versionRegexes:[]},{name:"Solaris",search:ae("sunos"),versionRegexes:[]},{name:"FreeBSD",search:ae("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:ae("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],de={browsers:p(ce),oses:p(ue)},me="Edge",he="Chromium",ge="Opera",pe="Firefox",fe="Safari",ve=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isEdge:r(me),isChromium:r(he),isIE:r("IE"),isOpera:r(ge),isFirefox:r(pe),isSafari:r(fe)}},we=()=>ve({current:void 0,version:se.unknown()}),ye=ve,be=(p(me),p(he),p("IE"),p(ge),p(pe),p(fe),"Windows"),Se="Android",xe="Linux",Ee="macOS",Fe="Solaris",Oe="FreeBSD",ke="ChromeOS",Te=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isWindows:r(be),isiOS:r("iOS"),isAndroid:r(Se),isMacOS:r(Ee),isLinux:r(xe),isSolaris:r(Fe),isFreeBSD:r(Oe),isChromeOS:r(ke)}},Ce=()=>Te({current:void 0,version:se.unknown()}),Ae=Te,Re=(p(be),p("iOS"),p(Se),p(xe),p(Ee),p(Fe),p(Oe),p(ke),(e,t,n)=>{const r=de.browsers(),o=de.oses(),s=t.bind((e=>((e,t)=>((e,t)=>{for(let n=0;n{const n=t.brand.toLowerCase();return F(e,(e=>{var t;return n===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:se.nu(parseInt(t.version,10),0)})))})))(r,e))).orThunk((()=>((e,t)=>ie(e,t).map((e=>{const n=se.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(r,e))).fold(we,ye),i=((e,t)=>ie(e,t).map((e=>{const n=se.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(o,e).fold(Ce,Ae),l=((e,t,n,r)=>{const o=e.isiOS()&&!0===/ipad/i.test(n),s=e.isiOS()&&!o,i=e.isiOS()||e.isAndroid(),l=i||r("(pointer:coarse)"),a=o||!s&&i&&r("(min-device-width:768px)"),c=s||i&&!a,u=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(n),d=!c&&!a&&!u;return{isiPad:p(o),isiPhone:p(s),isTablet:p(a),isPhone:p(c),isTouch:p(l),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:p(u),isDesktop:p(d)}})(i,s,e,n);return{browser:s,os:i,deviceType:l}}),Le=e=>window.matchMedia(e).matches;let Me=(e=>{let t,n=!1;return(...r)=>(n||(n=!0,t=e.apply(null,r)),t)})((()=>Re(window.navigator.userAgent,y.from(window.navigator.userAgentData),Le)));const Pe=(e,t)=>({left:e,top:t,translate:(n,r)=>Pe(e+n,t+r)}),De=Pe,Ne=e=>{const t=void 0===e?window:e;return Me().browser.isFirefox()?y.none():y.from(t.visualViewport)},He=(e,t,n,r)=>({x:e,y:t,width:n,height:r,right:e+n,bottom:t+r}),Ve=e=>{const t=void 0===e?window:e,n=t.document,r=(e=>{const t=void 0!==e?e.dom:document,n=t.body.scrollLeft||t.documentElement.scrollLeft,r=t.body.scrollTop||t.documentElement.scrollTop;return De(n,r)})(I(n));return Ne(t).fold((()=>{const e=t.document.documentElement,n=e.clientWidth,o=e.clientHeight;return He(r.left,r.top,n,o)}),(e=>He(Math.max(e.pageLeft,r.left),Math.max(e.pageTop,r.top),e.width,e.height)))},We=(e,t,n)=>Ne(n).map((n=>{const r=e=>t(Z(e));return n.addEventListener(e,r),{unbind:()=>n.removeEventListener(e,r)}})).getOrThunk((()=>({unbind:g})));var qe=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),Be=tinymce.util.Tools.resolve("tinymce.Env");const Ie=(e,t)=>{e.dispatch("FullscreenStateChanged",{state:t}),e.dispatch("ResizeEditor")},je=("fullscreen_native",e=>e.options.get("fullscreen_native"));const _e=e=>{return e.dom===(void 0!==(t=_(e).dom).fullscreenElement?t.fullscreenElement:void 0!==t.msFullscreenElement?t.msFullscreenElement:void 0!==t.webkitFullscreenElement?t.webkitFullscreenElement:null);var t},ze=(e,t,n)=>((e,t,n)=>E(((e,t)=>{const n=m(t)?t:v;let r=e.dom;const o=[];for(;null!==r.parentNode&&void 0!==r.parentNode;){const e=r.parentNode,t=I(e);if(o.push(t),!0===n(t))break;r=e}return o})(e,n),t))(e,(e=>j(e,t)),n),Ke=(e,t)=>((e,n)=>{return E((e=>y.from(e.dom.parentNode).map(I))(r=e).map(z).map((e=>E(e,(e=>{return t=e,!(r.dom===t.dom);var t})))).getOr([]),(e=>j(e,t)));var r})(e),$e="data-ephox-mobile-fullscreen-style",Ue="position:absolute!important;",Xe="top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;",Ye=Be.os.isAndroid(),Ge=(e,t,n)=>{const r=t=>n=>{const r=H(n,"style"),o=void 0===r?"no-styles":r.trim();o!==t&&(((e,t,n)=>{((e,t,n)=>{if(!(s(n)||c(n)||h(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(e.dom,t,n)})(n,$e,o),G(n,e.parseStyle(t)))},o=ze(t,"*"),i=(e=>{const t=[];for(let n=0,r=e.length;nKe(e,"*:not(.tox-silver-sink)")))),a=(e=>{const t=J(e,"background-color");return void 0!==t&&""!==t?"background-color:"+t+"!important":"background-color:rgb(255,255,255)!important;"})(n);x(i,r("display:none!important;")),x(o,r(Ue+Xe+a)),r((!0===Ye?"":Ue)+Xe+a)(t)},Je=qe.DOM,Qe=Ne().fold((()=>({bind:g,unbind:g})),(e=>{const t=(()=>{const e=O(g);return{...e,on:t=>e.get().each(t)}})(),n=k(),r=k(),o=((e,t)=>{let n=null;return{cancel:()=>{a(n)||(clearTimeout(n),n=null)},throttle:(...t)=>{a(n)&&(n=setTimeout((()=>{n=null,e.apply(null,t)}),50))}}})((()=>{document.body.scrollTop=0,document.documentElement.scrollTop=0,window.requestAnimationFrame((()=>{t.on((t=>G(t,{top:e.offsetTop+"px",left:e.offsetLeft+"px",height:e.height+"px",width:e.width+"px"})))}))}));return{bind:e=>{t.set(e),o.throttle(),n.set(We("resize",o.throttle)),r.set(We("scroll",o.throttle))},unbind:()=>{t.on((()=>{n.clear(),r.clear()})),t.clear()}}})),Ze=(e,t)=>{const n=document.body,r=document.documentElement,o=e.getContainer(),s=I(o),i=(l=s,y.from(l.dom.nextSibling).map(I)).filter((e=>(e=>P(e)&&L(e.dom))(e)&&((e,t)=>(e=>void 0!==e.dom.classList)(e)&&e.dom.classList.contains("tox-silver-sink"))(e)));var l;const a=(e=>{const t=I(e.getElement());return K(t).map($).getOrThunk((()=>(e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return I(t)})(_(t))))})(e),c=t.get(),u=I(e.getBody()),d=Be.deviceType.isTouch(),m=o.style,h=e.iframeElement,g=null==h?void 0:h.style,p=e=>{e(n,"tox-fullscreen"),e(r,"tox-fullscreen"),e(o,"tox-fullscreen"),K(s).map((e=>$(e).dom)).each((t=>{e(t,"tox-fullscreen"),e(t,"tox-shadowhost")}))},f=()=>{d&&(e=>{const t=((e,t)=>{const n=document;return 1!==(r=n).nodeType&&9!==r.nodeType&&11!==r.nodeType||0===r.childElementCount?[]:S(n.querySelectorAll(e),I);var r})("["+$e+"]");x(t,(t=>{const n=H(t,$e);n&&"no-styles"!==n?G(t,e.parseStyle(n)):V(t,"style"),V(t,$e)}))})(e.dom),p(Je.removeClass),Qe.unbind(),y.from(t.get()).each((e=>e.fullscreenChangeHandler.unbind()))};if(c)c.fullscreenChangeHandler.unbind(),je(e)&&_e(a)&&(e=>{const t=e.dom;t.exitFullscreen?t.exitFullscreen():t.msExitFullscreen?t.msExitFullscreen():t.webkitCancelFullScreen&&t.webkitCancelFullScreen()})(_(a)),g.width=c.iframeWidth,g.height=c.iframeHeight,m.width=c.containerWidth,m.height=c.containerHeight,m.top=c.containerTop,m.left=c.containerLeft,w=i,b=c.sinkCssPosition,E=(e,t)=>{Y(e,"position",t)},w.isSome()&&b.isSome()?y.some(E(w.getOrDie(),b.getOrDie())):y.none(),f(),v=c.scrollPos,window.scrollTo(v.x,v.y),t.set(null),Ie(e,!1),e.off("remove",f);else{const n=ne(_(a),void 0!==document.fullscreenElement?"fullscreenchange":void 0!==document.msFullscreenElement?"MSFullscreenChange":void 0!==document.webkitFullscreenElement?"webkitfullscreenchange":"fullscreenchange",(n=>{je(e)&&(_e(a)||null===t.get()||Ze(e,t))})),r={scrollPos:Ve(window),containerWidth:m.width,containerHeight:m.height,containerTop:m.top,containerLeft:m.left,iframeWidth:g.width,iframeHeight:g.height,fullscreenChangeHandler:n,sinkCssPosition:i.map((e=>J(e,"position")))};d&&Ge(e.dom,s,u),g.width=g.height="100%",m.width=m.height="",p(Je.addClass),i.each((e=>{Y(e,"position","fixed")})),Qe.bind(s),e.on("remove",f),t.set(r),je(e)&&(e=>{const t=e.dom;t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.webkitRequestFullScreen&&t.webkitRequestFullScreen()})(a),Ie(e,!0)}var v,w,b,E};var et=tinymce.util.Tools.resolve("tinymce.util.VK");const tt=(e,t)=>n=>{n.setActive(null!==t.get());const r=e=>n.setActive(e.state);return e.on("FullscreenStateChanged",r),()=>e.off("FullscreenStateChanged",r)};t.add("fullscreen",(t=>{const n=e(null);return t.inline||((e=>{(0,e.options.register)("fullscreen_native",{processor:"boolean",default:!1})})(t),((e,t)=>{e.addCommand("mceFullScreen",(()=>{Ze(e,t)}))})(t,n),((e,t)=>{const n=()=>e.execCommand("mceFullScreen");e.ui.registry.addToggleMenuItem("fullscreen",{text:"Fullscreen",icon:"fullscreen",shortcut:"Meta+Shift+F",onAction:n,onSetup:tt(e,t)}),e.ui.registry.addToggleButton("fullscreen",{tooltip:"Fullscreen",icon:"fullscreen",onAction:n,onSetup:tt(e,t),shortcut:"Meta+Shift+F"})})(t,n),((e,t)=>{e.on("init",(()=>{e.on("keydown",(e=>{e.keyCode!==et.TAB||e.metaKey||e.ctrlKey||!t.get()||e.preventDefault()}))}))})(t,n),t.addShortcut("Meta+Shift+F","","mceFullScreen")),(e=>({isFullscreen:()=>null!==e.get()}))(n)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ar.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ar.js new file mode 100644 index 0000000..e2cf02f --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ar.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ar', +'

بدء التنقل بواسطة لوحة المفاتيح

\n' + + '\n' + + '
\n' + + '
التركيز على شريط القوائم
\n' + + '
نظاما التشغيل Windows أو Linux: Alt + F9
\n' + + '
نظام التشغيل macOS: ⌥F9
\n' + + '
التركيز على شريط الأدوات
\n' + + '
نظاما التشغيل Windows أو Linux: Alt + F10
\n' + + '
نظام التشغيل macOS: ⌥F10
\n' + + '
التركيز على التذييل
\n' + + '
نظاما التشغيل Windows أو Linux: Alt + F11
\n' + + '
نظام التشغيل macOS: ⌥F11
\n' + + '
تركيز الإشعارات
\n' + + '
نظاما التشغيل Windows أو Linux: Alt + F12
\n' + + '
نظام التشغيل macOS: ⌥F12
\n' + + '
التركيز على شريط أدوات السياق
\n' + + '
أنظمة التشغيل Windows أو Linux أو macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

سيبدأ التنقل عند عنصر واجهة المستخدم الأول، والذي سيتم تمييزه أو تسطيره في حالة العنصر الأول في\n' + + ' مسار عنصر التذييل.

\n' + + '\n' + + '

التنقل بين أقسام واجهة المستخدم

\n' + + '\n' + + '

للانتقال من أحد أقسام واجهة المستخدم إلى القسم التالي، اضغط على Tab.

\n' + + '\n' + + '

للانتقال من أحد أقسام واجهة المستخدم إلى القسم السابق، اضغط على Shift+Tab.

\n' + + '\n' + + '

ترتيب علامات Tab لأقسام واجهة المستخدم هذه هو:

\n' + + '\n' + + '
    \n' + + '
  1. شريط القوائم
  2. \n' + + '
  3. كل مجموعة شريط الأدوات
  4. \n' + + '
  5. الشريط الجانبي
  6. \n' + + '
  7. مسار العنصر في التذييل
  8. \n' + + '
  9. زر تبديل عدد الكلمات في التذييل
  10. \n' + + '
  11. رابط إدراج العلامة التجارية في التذييل
  12. \n' + + '
  13. مؤشر تغيير حجم المحرر في التذييل
  14. \n' + + '
\n' + + '\n' + + '

إذا لم يكن قسم واجهة المستخدم موجودًا، فسيتم تخطيه.

\n' + + '\n' + + '

إذا كان التذييل يحتوي على التركيز على ‏‫التنقل بواسطة لوحة المفاتيح، ولا يوجد شريط جانبي مرئي، فإن الضغط على Shift+Tab\n' + + ' ينقل التركيز إلى مجموعة شريط الأدوات الأولى، وليس الأخيرة.

\n' + + '\n' + + '

التنقل بين أقسام واجهة المستخدم

\n' + + '\n' + + '

للانتقال من أحد عناصر واجهة المستخدم إلى العنصر التالي، اضغط على مفتاح السهم المناسب.

\n' + + '\n' + + '

مفتاحا السهمين اليسار‎ واليمين‎

\n' + + '\n' + + '
    \n' + + '
  • التنقل بين القوائم في شريط القوائم.
  • \n' + + '
  • فتح قائمة فرعية في القائمة.
  • \n' + + '
  • التنقل بين الأزرار في مجموعة شريط الأدوات.
  • \n' + + '
  • التنقل بين العناصر في مسار عنصر التذييل.
  • \n' + + '
\n' + + '\n' + + '

مفتاحا السهمين لأسفل‎ ولأعلى‎

\n' + + '\n' + + '
    \n' + + '
  • التنقل بين عناصر القائمة في القائمة.
  • \n' + + '
  • التنقل بين العناصر في قائمة شريط الأدوات المنبثقة.
  • \n' + + '
\n' + + '\n' + + '

دورة مفاتيح الأسهم‎ داخل قسم واجهة المستخدم التي تم التركيز عليها.

\n' + + '\n' + + '

لإغلاق قائمة مفتوحة أو قائمة فرعية مفتوحة أو قائمة منبثقة مفتوحة، اضغط على مفتاح Esc.

\n' + + '\n' + + '

إذا كان التركيز الحالي على "الجزء العلوي" من قسم معين لواجهة المستخدم، فإن الضغط على مفتاح Esc يؤدي أيضًا إلى الخروج\n' + + ' من التنقل بواسطة لوحة المفاتيح بالكامل.

\n' + + '\n' + + '

تنفيذ عنصر قائمة أو زر شريط أدوات

\n' + + '\n' + + '

عندما يتم تمييز عنصر القائمة المطلوب أو زر شريط الأدوات، اضغط على زر Return، أو Enter،\n' + + ' أو مفتاح المسافة لتنفيذ العنصر.

\n' + + '\n' + + '

التنقل في مربعات الحوار غير المبوبة

\n' + + '\n' + + '

في مربعات الحوار غير المبوبة، يتم التركيز على المكون التفاعلي الأول عند فتح مربع الحوار.

\n' + + '\n' + + '

التنقل بين مكونات الحوار التفاعلي بالضغط على زر Tab أو Shift+Tab.

\n' + + '\n' + + '

التنقل في مربعات الحوار المبوبة

\n' + + '\n' + + '

في مربعات الحوار المبوبة، يتم التركيز على الزر الأول في قائمة علامات التبويب عند فتح مربع الحوار.

\n' + + '\n' + + '

التنقل بين المكونات التفاعلية لعلامة التبويب لمربع الحوار هذه بالضغط على زر Tab أو\n' + + ' Shift+Tab.

\n' + + '\n' + + '

التبديل إلى علامة تبويب أخرى لمربع الحوار من خلال التركيز على قائمة علامة التبويب ثم الضغط على زر السهم المناسب\n' + + ' مفتاح للتنقل بين علامات التبويب المتاحة.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/bg_BG.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/bg_BG.js new file mode 100644 index 0000000..09eacf3 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/bg_BG.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.bg_BG', +'

Начало на навигацията с клавиатурата

\n' + + '\n' + + '
\n' + + '
Фокусиране върху лентата с менюта
\n' + + '
Windows или Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Фокусиране върху лентата с инструменти
\n' + + '
Windows или Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Фокусиране върху долния колонтитул
\n' + + '
Windows или Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Фокусиране на известието
\n' + + '
Windows или Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Фокусиране върху контекстуалната лента с инструменти
\n' + + '
Windows, Linux или macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Навигацията ще започне с първия елемент на ПИ, който ще бъде маркиран или подчертан в случая на първия елемент в\n' + + ' пътя до елемента в долния колонтитул.

\n' + + '\n' + + '

Навигиране между раздели на ПИ

\n' + + '\n' + + '

За да преминете от един раздел на ПИ към следващия, натиснете Tab.

\n' + + '\n' + + '

За да преминете от един раздел на ПИ към предишния, натиснете Shift+Tab.

\n' + + '\n' + + '

Редът за обхождане с табулация на тези раздели на ПИ е:

\n' + + '\n' + + '
    \n' + + '
  1. Лентата с менюта
  2. \n' + + '
  3. Всяка група на лентата с инструменти
  4. \n' + + '
  5. Страничната лента
  6. \n' + + '
  7. Пътят до елемента в долния колонтитул
  8. \n' + + '
  9. Бутонът за превключване на броя на думите в долния колонтитул
  10. \n' + + '
  11. Връзката за търговска марка в долния колонтитул
  12. \n' + + '
  13. Манипулаторът за преоразмеряване на редактора в долния колонтитул
  14. \n' + + '
\n' + + '\n' + + '

Ако някой раздел на ПИ липсва, той се пропуска.

\n' + + '\n' + + '

Ако долният колонтитул има фокус за навигация с клавиатурата и няма странична лента, натискането на Shift+Tab\n' + + ' премества фокуса към първата група на лентата с инструменти, а не към последната.

\n' + + '\n' + + '

Навигиране в разделите на ПИ

\n' + + '\n' + + '

За да преминете от един елемент на ПИ към следващия, натиснете съответния клавиш със стрелка.

\n' + + '\n' + + '

С клавишите със стрелка наляво и надясно

\n' + + '\n' + + '
    \n' + + '
  • се придвижвате между менютата в лентата с менюто;
  • \n' + + '
  • отваряте подменю в меню;
  • \n' + + '
  • се придвижвате между бутоните в група на лентата с инструменти;
  • \n' + + '
  • се придвижвате между елементи в пътя до елемент в долния колонтитул.
  • \n' + + '
\n' + + '\n' + + '

С клавишите със стрелка надолу и нагоре

\n' + + '\n' + + '
    \n' + + '
  • се придвижвате между елементите от менюто в дадено меню;
  • \n' + + '
  • се придвижвате между елементите в изскачащо меню на лентата с инструменти.
  • \n' + + '
\n' + + '\n' + + '

Клавишите със стрелки се придвижват в рамките на фокусирания раздел на ПИ.

\n' + + '\n' + + '

За да затворите отворено меню, подменю или изскачащо меню, натиснете клавиша Esc.

\n' + + '\n' + + '

Ако текущият фокус е върху „горната част“ на конкретен раздел на ПИ, натискането на клавиша Esc също излиза\n' + + ' напълно от навигацията с клавиатурата.

\n' + + '\n' + + '

Изпълнение на елемент от менюто или бутон от лентата с инструменти

\n' + + '\n' + + '

Когато желаният елемент от менюто или бутон от лентата с инструменти е маркиран, натиснете Return, Enter\n' + + ' или клавиша за интервал, за да изпълните елемента.

\n' + + '\n' + + '

Навигиране в диалогови прозорци без раздели

\n' + + '\n' + + '

В диалоговите прозорци без раздели първият интерактивен компонент се фокусира, когато се отвори диалоговият прозорец.

\n' + + '\n' + + '

Навигирайте между интерактивните компоненти на диалоговия прозорец, като натиснете Tab или Shift+Tab.

\n' + + '\n' + + '

Навигиране в диалогови прозорци с раздели

\n' + + '\n' + + '

В диалоговите прозорци с раздели първият бутон в менюто с раздели се фокусира, когато се отвори диалоговият прозорец.

\n' + + '\n' + + '

Навигирайте между интерактивните компоненти на този диалогов раздел, като натиснете Tab или\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Превключете към друг диалогов раздел, като фокусирате върху менюто с раздели и след това натиснете съответния клавиш със стрелка,\n' + + ' за да преминете през наличните раздели.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ca.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ca.js new file mode 100644 index 0000000..996e29c --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ca.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ca', +'

Inici de la navegació amb el teclat

\n' + + '\n' + + '
\n' + + '
Enfocar la barra de menús
\n' + + '
Windows o Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + "
Enfocar la barra d'eines
\n" + + '
Windows o Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Enfocar el peu de pàgina
\n' + + '
Windows o Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Enfocar la notificació
\n' + + '
Windows o Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + "
Enfocar una barra d'eines contextual
\n" + + '
Windows, Linux o macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + "

La navegació començarà en el primer element de la interfície d'usuari, que es ressaltarà o subratllarà per al primer element a\n" + + " la ruta de l'element de peu de pàgina.

\n" + + '\n' + + "

Navegació entre seccions de la interfície d'usuari

\n" + + '\n' + + "

Per desplaçar-vos des d'una secció de la interfície d'usuari a la següent, premeu la tecla Tab.

\n" + + '\n' + + "

Per desplaçar-vos des d'una secció de la interfície d'usuari a l'anterior, premeu les tecles Maj+Tab.

\n" + + '\n' + + "

L'ordre en prémer la tecla Tab d'aquestes secciones de la interfície d'usuari és:

\n" + + '\n' + + '
    \n' + + '
  1. Barra de menús
  2. \n' + + "
  3. Cada grup de la barra d'eines
  4. \n" + + '
  5. Barra lateral
  6. \n' + + "
  7. Ruta de l'element del peu de pàgina
  8. \n" + + '
  9. Botó de commutació de recompte de paraules al peu de pàgina
  10. \n' + + '
  11. Enllaç de marca del peu de pàgina
  12. \n' + + "
  13. Control de canvi de mida de l'editor al peu de pàgina
  14. \n" + + '
\n' + + '\n' + + "

Si no hi ha una secció de la interfície d'usuari, s'ometrà.

\n" + + '\n' + + '

Si el peu de pàgina té el focus de navegació del teclat i no hi ha cap barra lateral visible, en prémer Maj+Tab\n' + + " el focus es mou al primer grup de la barra d'eines, no l'últim.

\n" + + '\n' + + "

Navegació dins de les seccions de la interfície d'usuari

\n" + + '\n' + + "

Per desplaçar-vos des d'un element de la interfície d'usuari al següent, premeu la tecla de Fletxa adequada.

\n" + + '\n' + + '

Les tecles de fletxa Esquerra i Dreta

\n' + + '\n' + + '
    \n' + + '
  • us permeten desplaçar-vos entre menús de la barra de menús.
  • \n' + + '
  • obren un submenú en un menú.
  • \n' + + "
  • us permeten desplaçar-vos entre botons d'un grup de la barra d'eines.
  • \n" + + "
  • us permeten desplaçar-vos entre elements de la ruta d'elements del peu de pàgina.
  • \n" + + '
\n' + + '\n' + + '

Les tecles de fletxa Avall i Amunt

\n' + + '\n' + + '
    \n' + + "
  • us permeten desplaçar-vos entre elements de menú d'un menú.
  • \n" + + "
  • us permeten desplaçar-vos entre elements d'un menú emergent de la barra d'eines.
  • \n" + + '
\n' + + '\n' + + "

Les tecles de Fletxa us permeten desplaçar-vos dins de la secció de la interfície d'usuari que té el focus.

\n" + + '\n' + + '

Per tancar un menú, un submenú o un menú emergent oberts, premeu la tecla Esc.

\n' + + '\n' + + "

Si el focus actual es troba a la ‘part superior’ d'una secció específica de la interfície d'usuari, en prémer la tecla Esc també es tanca\n" + + ' completament la navegació amb el teclat.

\n' + + '\n' + + "

Execució d'un element de menú o d'un botó de la barra d'eines

\n" + + '\n' + + "

Quan l'element del menú o el botó de la barra d'eines que desitgeu estigui ressaltat, premeu Retorn, Intro\n" + + " o la barra d'espai per executar l'element.

\n" + + '\n' + + '

Navegació per quadres de diàleg sense pestanyes

\n' + + '\n' + + "

En els quadres de diàleg sense pestanyes, el primer component interactiu pren el focus quan s'obre el quadre diàleg.

\n" + + '\n' + + '

Premeu la tecla Tab o les tecles Maj+Tab per desplaçar-vos entre components interactius del quadre de diàleg.

\n' + + '\n' + + '

Navegació per quadres de diàleg amb pestanyes

\n' + + '\n' + + "

En els quadres de diàleg amb pestanyes, el primer botó del menú de la pestanya pren el focus quan s'obre el quadre diàleg.

\n" + + '\n' + + "

Per desplaçar-vos entre components interactius d'aquest quadre de diàleg, premeu la tecla Tab o\n" + + ' les tecles Maj+Tab.

\n' + + '\n' + + "

Canvieu a la pestanya d'un altre quadre de diàleg, tot enfocant el menú de la pestanya, i després premeu la tecla Fletxa adequada\n" + + ' per canviar entre les pestanyes disponibles.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/cs.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/cs.js new file mode 100644 index 0000000..4a5a902 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/cs.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.cs', +'

Začínáme navigovat pomocí klávesnice

\n' + + '\n' + + '
\n' + + '
Přejít na řádek nabídek
\n' + + '
Windows nebo Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Přejít na panel nástrojů
\n' + + '
Windows nebo Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Přejít na zápatí
\n' + + '
Windows nebo Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Přejít na oznámení
\n' + + '
Windows nebo Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Přejít na kontextový panel nástrojů
\n' + + '
Windows, Linux nebo macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigace začne u první položky uživatelského rozhraní, která bude zvýrazněna nebo v případě první položky\n' + + ' cesty k prvku zápatí podtržena.

\n' + + '\n' + + '

Navigace mezi oddíly uživatelského rozhraní

\n' + + '\n' + + '

Stisknutím klávesy Tab se posunete z jednoho oddílu uživatelského rozhraní na další.

\n' + + '\n' + + '

Stisknutím kláves Shift+Tab se posunete z jednoho oddílu uživatelského rozhraní na předchozí.

\n' + + '\n' + + '

Pořadí přepínání mezi oddíly uživatelského rozhraní pomocí klávesy Tab:

\n' + + '\n' + + '
    \n' + + '
  1. Řádek nabídek
  2. \n' + + '
  3. Každá skupina panelu nástrojů
  4. \n' + + '
  5. Boční panel
  6. \n' + + '
  7. Cesta k prvku v zápatí.
  8. \n' + + '
  9. Tlačítko přepínače počtu slov v zápatí
  10. \n' + + '
  11. Odkaz na informace o značce v zápatí
  12. \n' + + '
  13. Úchyt pro změnu velikosti editoru v zápatí
  14. \n' + + '
\n' + + '\n' + + '

Pokud nějaký oddíl uživatelského rozhraní není přítomen, je přeskočen.

\n' + + '\n' + + '

Pokud je zápatí vybrané pro navigaci pomocí klávesnice a není zobrazen žádný boční panel, stisknutím kláves Shift+Tab\n' + + ' přejdete na první skupinu panelu nástrojů, nikoli na poslední.

\n' + + '\n' + + '

Navigace v rámci oddílů uživatelského rozhraní

\n' + + '\n' + + '

Chcete-li se přesunout z jednoho prvku uživatelského rozhraní na další, stiskněte příslušnou klávesu s šipkou.

\n' + + '\n' + + '

Klávesy s šipkou vlevovpravo

\n' + + '\n' + + '
    \n' + + '
  • umožňují přesun mezi nabídkami na řádku nabídek;
  • \n' + + '
  • otevírají podnabídku nabídky;
  • \n' + + '
  • umožňují přesun mezi tlačítky ve skupině panelu nástrojů;
  • \n' + + '
  • umožňují přesun mezi položkami cesty prvku v zápatí.
  • \n' + + '
\n' + + '\n' + + '

Klávesy se šipkou dolůnahoru

\n' + + '\n' + + '
    \n' + + '
  • umožňují přesun mezi položkami nabídky;
  • \n' + + '
  • umožňují přesun mezi položkami místní nabídky panelu nástrojů.
  • \n' + + '
\n' + + '\n' + + '

Šipky provádí přepínání v rámci vybraného oddílu uživatelského rozhraní.

\n' + + '\n' + + '

Chcete-li zavřít otevřenou nabídku, podnabídku nebo místní nabídku, stiskněte klávesu Esc.

\n' + + '\n' + + '

Pokud je aktuálně vybrána horní část oddílu uživatelského rozhraní, stisknutím klávesy Esc zcela ukončíte také\n' + + ' navigaci pomocí klávesnice.

\n' + + '\n' + + '

Provedení příkazu položky nabídky nebo tlačítka panelu nástrojů

\n' + + '\n' + + '

Pokud je zvýrazněna požadovaná položka nabídky nebo tlačítko panelu nástrojů, stisknutím klávesy Return, Enter\n' + + ' nebo mezerníku provedete příslušný příkaz.

\n' + + '\n' + + '

Navigace v dialogových oknech bez záložek

\n' + + '\n' + + '

Při otevření dialogových oken bez záložek přejdete na první interaktivní komponentu.

\n' + + '\n' + + '

Přecházet mezi interaktivními komponentami dialogového okna můžete stisknutím klávesy Tab nebo kombinace Shift+Tab.

\n' + + '\n' + + '

Navigace v dialogových oknech se záložkami

\n' + + '\n' + + '

Při otevření dialogových oken se záložkami přejdete na první tlačítko v nabídce záložek.

\n' + + '\n' + + '

Přecházet mezi interaktivními komponentami této záložky dialogového okna můžete stisknutím klávesy Tab nebo\n' + + ' kombinace Shift+Tab.

\n' + + '\n' + + '

Chcete-li přepnout na další záložku dialogového okna, přejděte na nabídku záložek a poté můžete stisknutím požadované šipky\n' + + ' přepínat mezi dostupnými záložkami.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/da.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/da.js new file mode 100644 index 0000000..4d1e1d4 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/da.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.da', +'

Start tastaturnavigation

\n' + + '\n' + + '
\n' + + '
Fokuser på menulinjen
\n' + + '
Windows eller Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokuser på værktøjslinjen
\n' + + '
Windows eller Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokuser på sidefoden
\n' + + '
Windows eller Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Fokuser på meddelelsen
\n' + + '
Windows eller Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokuser på kontekstuel værktøjslinje
\n' + + '
Windows, Linux eller macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigationen starter ved det første UI-element, som fremhæves eller understreges hvad angår det første element i\n' + + ' sidefodens sti til elementet.

\n' + + '\n' + + '

Naviger mellem UI-sektioner

\n' + + '\n' + + '

Gå fra én UI-sektion til den næste ved at trykke på Tab.

\n' + + '\n' + + '

Gå fra én UI-sektion til den forrige ved at trykke på Shift+Tab.

\n' + + '\n' + + '

Tab-rækkefølgen af disse UI-sektioner er:

\n' + + '\n' + + '
    \n' + + '
  1. Menulinje
  2. \n' + + '
  3. Hver værktøjsgruppe
  4. \n' + + '
  5. Sidepanel
  6. \n' + + '
  7. Sti til elementet i sidefoden
  8. \n' + + '
  9. Til/fra-knap for ordoptælling i sidefoden
  10. \n' + + '
  11. Brandinglink i sidefoden
  12. \n' + + '
  13. Tilpasningshåndtag for editor i sidefoden
  14. \n' + + '
\n' + + '\n' + + '

Hvis en UI-sektion ikke er til stede, springes den over.

\n' + + '\n' + + '

Hvis sidefoden har fokus til tastaturnavigation, og der ikke er noget synligt sidepanel, kan der trykkes på Shift+Tab\n' + + ' for at flytte fokus til den første værktøjsgruppe, ikke den sidste.

\n' + + '\n' + + '

Naviger inden for UI-sektioner

\n' + + '\n' + + '

Gå fra ét UI-element til det næste ved at trykke på den relevante piletast.

\n' + + '\n' + + '

Venstre og højre piletast

\n' + + '\n' + + '
    \n' + + '
  • flytter mellem menuerne i menulinjen.
  • \n' + + '
  • åbner en undermenu i en menu.
  • \n' + + '
  • flytter mellem knapperne i en værktøjsgruppe.
  • \n' + + '
  • flytter mellem elementer i sidefodens sti til elementet.
  • \n' + + '
\n' + + '\n' + + '

Pil ned og op

\n' + + '\n' + + '
    \n' + + '
  • flytter mellem menupunkterne i en menu.
  • \n' + + '
  • flytter mellem punkterne i en genvejsmenu i værktøjslinjen.
  • \n' + + '
\n' + + '\n' + + '

Piletasterne kører rundt inden for UI-sektionen, der fokuseres på.

\n' + + '\n' + + '

For at lukke en åben menu, en åben undermenu eller en åben genvejsmenu trykkes der på Esc-tasten.

\n' + + '\n' + + "

Hvis det aktuelle fokus er i 'toppen' af en bestemt UI-sektion, vil tryk på Esc-tasten også afslutte\n" + + ' tastaturnavigationen helt.

\n' + + '\n' + + '

Udfør et menupunkt eller en værktøjslinjeknap

\n' + + '\n' + + '

Når det ønskede menupunkt eller den ønskede værktøjslinjeknap er fremhævet, trykkes der på Retur, Enter\n' + + ' eller mellemrumstasten for at udføre elementet.

\n' + + '\n' + + '

Naviger i ikke-faneopdelte dialogbokse

\n' + + '\n' + + '

I ikke-faneopdelte dialogbokse får den første interaktive komponent fokus, når dialogboksen åbnes.

\n' + + '\n' + + '

Naviger mellem interaktive dialogbokskomponenter ved at trykke på Tab eller Shift+Tab.

\n' + + '\n' + + '

Naviger i faneopdelte dialogbokse

\n' + + '\n' + + '

I faneopdelte dialogbokse får den første knap i fanemenuen fokus, når dialogboksen åbnes.

\n' + + '\n' + + '

Naviger mellem interaktive komponenter i denne dialogboksfane ved at trykke på Tab eller\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Skift til en anden dialogboksfane ved at fokusere på fanemenuen og derefter trykke på den relevante piletast\n' + + ' for at køre igennem de tilgængelige faner.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/de.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/de.js new file mode 100644 index 0000000..b8711ed --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/de.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.de', +'

Grundlagen der Tastaturnavigation

\n' + + '\n' + + '
\n' + + '
Fokus auf Menüleiste
\n' + + '
Windows oder Linux: ALT+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokus auf Symbolleiste
\n' + + '
Windows oder Linux: ALT+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokus auf Fußzeile
\n' + + '
Windows oder Linux: ALT+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Benachrichtigung fokussieren
\n' + + '
Windows oder Linux: ALT+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokus auf kontextbezogene Symbolleiste
\n' + + '
Windows, Linux oder macOS: STRG+F9
\n' + + '
\n' + + '\n' + + '

Die Navigation beginnt beim ersten Benutzeroberflächenelement, welches hervorgehoben ist. Falls sich das erste Element im Pfad der Fußzeile befindet,\n' + + ' ist es unterstrichen.

\n' + + '\n' + + '

Zwischen Abschnitten der Benutzeroberfläche navigieren

\n' + + '\n' + + '

Um von einem Abschnitt der Benutzeroberfläche zum nächsten zu wechseln, drücken Sie TAB.

\n' + + '\n' + + '

Um von einem Abschnitt der Benutzeroberfläche zum vorherigen zu wechseln, drücken Sie UMSCHALT+TAB.

\n' + + '\n' + + '

Die Abschnitte der Benutzeroberfläche haben folgende TAB-Reihenfolge:

\n' + + '\n' + + '
    \n' + + '
  1. Menüleiste
  2. \n' + + '
  3. Einzelne Gruppen der Symbolleiste
  4. \n' + + '
  5. Randleiste
  6. \n' + + '
  7. Elementpfad in der Fußzeile
  8. \n' + + '
  9. Umschaltfläche „Wörter zählen“ in der Fußzeile
  10. \n' + + '
  11. Branding-Link in der Fußzeile
  12. \n' + + '
  13. Editor-Ziehpunkt zur Größenänderung in der Fußzeile
  14. \n' + + '
\n' + + '\n' + + '

Falls ein Abschnitt der Benutzeroberflächen nicht vorhanden ist, wird er übersprungen.

\n' + + '\n' + + '

Wenn in der Fußzeile die Tastaturnavigation fokussiert ist und keine Randleiste angezeigt wird, wechselt der Fokus durch Drücken von UMSCHALT+TAB\n' + + ' zur ersten Gruppe der Symbolleiste, nicht zur letzten.

\n' + + '\n' + + '

Innerhalb von Abschnitten der Benutzeroberfläche navigieren

\n' + + '\n' + + '

Um von einem Element der Benutzeroberfläche zum nächsten zu wechseln, drücken Sie die entsprechende Pfeiltaste.

\n' + + '\n' + + '

Die Pfeiltasten Links und Rechts

\n' + + '\n' + + '
    \n' + + '
  • wechseln zwischen Menüs in der Menüleiste.
  • \n' + + '
  • öffnen das Untermenü eines Menüs.
  • \n' + + '
  • wechseln zwischen Schaltflächen in einer Gruppe der Symbolleiste.
  • \n' + + '
  • wechseln zwischen Elementen im Elementpfad der Fußzeile.
  • \n' + + '
\n' + + '\n' + + '

Die Pfeiltasten Abwärts und Aufwärts

\n' + + '\n' + + '
    \n' + + '
  • wechseln zwischen Menüelementen in einem Menü.
  • \n' + + '
  • wechseln zwischen Elementen in einem Popupmenü der Symbolleiste.
  • \n' + + '
\n' + + '\n' + + '

Die Pfeiltasten rotieren innerhalb des fokussierten Abschnitts der Benutzeroberfläche.

\n' + + '\n' + + '

Um ein geöffnetes Menü, ein geöffnetes Untermenü oder ein geöffnetes Popupmenü zu schließen, drücken Sie die ESC-Taste.

\n' + + '\n' + + '

Wenn sich der aktuelle Fokus ganz oben in einem bestimmten Abschnitt der Benutzeroberfläche befindet, wird durch Drücken der ESC-Taste auch\n' + + ' die Tastaturnavigation beendet.

\n' + + '\n' + + '

Ein Menüelement oder eine Symbolleistenschaltfläche ausführen

\n' + + '\n' + + '

Wenn das gewünschte Menüelement oder die gewünschte Symbolleistenschaltfläche hervorgehoben ist, drücken Sie Zurück, Eingabe\n' + + ' oder die Leertaste, um das Element auszuführen.

\n' + + '\n' + + '

In Dialogfeldern ohne Registerkarten navigieren

\n' + + '\n' + + '

In Dialogfeldern ohne Registerkarten ist beim Öffnen eines Dialogfelds die erste interaktive Komponente fokussiert.

\n' + + '\n' + + '

Navigieren Sie zwischen den interaktiven Komponenten eines Dialogfelds, indem Sie TAB oder UMSCHALT+TAB drücken.

\n' + + '\n' + + '

In Dialogfeldern mit Registerkarten navigieren

\n' + + '\n' + + '

In Dialogfeldern mit Registerkarten ist beim Öffnen eines Dialogfelds die erste Schaltfläche eines Registerkartenmenüs fokussiert.

\n' + + '\n' + + '

Navigieren Sie zwischen den interaktiven Komponenten auf dieser Registerkarte des Dialogfelds, indem Sie TAB oder\n' + + ' UMSCHALT+TAB drücken.

\n' + + '\n' + + '

Wechseln Sie zu einer anderen Registerkarte des Dialogfelds, indem Sie den Fokus auf das Registerkartenmenü legen und dann die entsprechende Pfeiltaste\n' + + ' drücken, um durch die verfügbaren Registerkarten zu rotieren.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/el.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/el.js new file mode 100644 index 0000000..98afabe --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/el.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.el', +'

Έναρξη πλοήγησης μέσω πληκτρολογίου

\n' + + '\n' + + '
\n' + + '
Εστίαση στη γραμμή μενού
\n' + + '
Windows ή Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Εστίαση στη γραμμή εργαλείων
\n' + + '
Windows ή Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Εστίαση στο υποσέλιδο
\n' + + '
Windows ή Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Εστίαση στην ειδοποίηση
\n' + + '
Windows ή Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Εστίαση σε γραμμή εργαλείων βάσει περιεχομένου
\n' + + '
Windows, Linux ή macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Η πλοήγηση θα ξεκινήσει από το πρώτο στοιχείο περιβάλλοντος χρήστη, που θα επισημαίνεται ή θα είναι υπογραμμισμένο,\n' + + ' όπως στην περίπτωση της διαδρομής του στοιχείου Υποσέλιδου.

\n' + + '\n' + + '

Πλοήγηση μεταξύ ενοτήτων του περιβάλλοντος χρήστη

\n' + + '\n' + + '

Για να μετακινηθείτε από μια ενότητα περιβάλλοντος χρήστη στην επόμενη, πιέστε το πλήκτρο Tab.

\n' + + '\n' + + '

Για να μετακινηθείτε από μια ενότητα περιβάλλοντος χρήστη στην προηγούμενη, πιέστε τα πλήκτρα Shift+Tab.

\n' + + '\n' + + '

Η σειρά Tab αυτών των ενοτήτων περιβάλλοντος χρήστη είναι η εξής:

\n' + + '\n' + + '
    \n' + + '
  1. Γραμμή μενού
  2. \n' + + '
  3. Κάθε ομάδα γραμμής εργαλείων
  4. \n' + + '
  5. Πλαϊνή γραμμή
  6. \n' + + '
  7. Διαδρομή στοιχείου στο υποσέλιδο
  8. \n' + + '
  9. Κουμπί εναλλαγής μέτρησης λέξεων στο υποσέλιδο
  10. \n' + + '
  11. Σύνδεσμος επωνυμίας στο υποσέλιδο
  12. \n' + + '
  13. Λαβή αλλαγής μεγέθους προγράμματος επεξεργασίας στο υποσέλιδο
  14. \n' + + '
\n' + + '\n' + + '

Εάν δεν εμφανίζεται ενότητα περιβάλλοντος χρήστη, παραλείπεται.

\n' + + '\n' + + '

Εάν η εστίαση πλοήγησης βρίσκεται στο πληκτρολόγιο και δεν υπάρχει εμφανής πλαϊνή γραμμή, εάν πιέσετε Shift+Tab\n' + + ' η εστίαση μετακινείται στην πρώτη ομάδα γραμμής εργαλείων, όχι στην τελευταία.

\n' + + '\n' + + '

Πλοήγηση εντός των ενοτήτων του περιβάλλοντος χρήστη

\n' + + '\n' + + '

Για να μετακινηθείτε από ένα στοιχείο περιβάλλοντος χρήστη στο επόμενο, πιέστε το αντίστοιχο πλήκτρο βέλους.

\n' + + '\n' + + '

Με τα πλήκτρα αριστερού και δεξιού βέλους

\n' + + '\n' + + '
    \n' + + '
  • γίνεται μετακίνηση μεταξύ των μενού στη γραμμή μενού.
  • \n' + + '
  • ανοίγει ένα υπομενού σε ένα μενού.
  • \n' + + '
  • γίνεται μετακίνηση μεταξύ κουμπιών σε μια ομάδα γραμμής εργαλείων.
  • \n' + + '
  • γίνεται μετακίνηση μεταξύ στοιχείων στη διαδρομή στοιχείου στο υποσέλιδο.
  • \n' + + '
\n' + + '\n' + + '

Με τα πλήκτρα επάνω και κάτω βέλους

\n' + + '\n' + + '
    \n' + + '
  • γίνεται μετακίνηση μεταξύ των στοιχείων μενού σε ένα μενού.
  • \n' + + '
  • γίνεται μετακίνηση μεταξύ των στοιχείων μενού σε ένα αναδυόμενο μενού γραμμής εργαλείων.
  • \n' + + '
\n' + + '\n' + + '

Με τα πλήκτρα βέλους γίνεται κυκλική μετακίνηση εντός της εστιασμένης ενότητας περιβάλλοντος χρήστη.

\n' + + '\n' + + '

Για να κλείσετε ένα ανοιχτό μενού, ένα ανοιχτό υπομενού ή ένα ανοιχτό αναδυόμενο μενού, πιέστε το πλήκτρο Esc.

\n' + + '\n' + + '

Εάν η τρέχουσα εστίαση βρίσκεται στην κορυφή μιας ενότητας περιβάλλοντος χρήστη, πιέζοντας το πλήκτρο Esc,\n' + + ' γίνεται επίσης πλήρης έξοδος από την πλοήγηση μέσω πληκτρολογίου.

\n' + + '\n' + + '

Εκτέλεση ενός στοιχείου μενού ή κουμπιού γραμμής εργαλείων

\n' + + '\n' + + '

Όταν το επιθυμητό στοιχείο μενού ή κουμπί γραμμής εργαλείων είναι επισημασμένο, πιέστε τα πλήκτρα Return, Enter,\n' + + ' ή το πλήκτρο διαστήματος για να εκτελέσετε το στοιχείο.

\n' + + '\n' + + '

Πλοήγηση σε παράθυρα διαλόγου χωρίς καρτέλες

\n' + + '\n' + + '

Σε παράθυρα διαλόγου χωρίς καρτέλες, το πρώτο αλληλεπιδραστικό στοιχείο λαμβάνει την εστίαση όταν ανοίγει το παράθυρο διαλόγου.

\n' + + '\n' + + '

Μπορείτε να πλοηγηθείτε μεταξύ των αλληλεπιδραστικών στοιχείων παραθύρων διαλόγων πιέζοντας τα πλήκτρα Tab ή Shift+Tab.

\n' + + '\n' + + '

Πλοήγηση σε παράθυρα διαλόγου με καρτέλες

\n' + + '\n' + + '

Σε παράθυρα διαλόγου με καρτέλες, το πρώτο κουμπί στο μενού καρτέλας λαμβάνει την εστίαση όταν ανοίγει το παράθυρο διαλόγου.

\n' + + '\n' + + '

Μπορείτε να πλοηγηθείτε μεταξύ των αλληλεπιδραστικών στοιχείων αυτής της καρτέλα διαλόγου πιέζοντας τα πλήκτρα Tab ή\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Μπορείτε να κάνετε εναλλαγή σε άλλη καρτέλα του παραθύρου διαλόγου, μεταφέροντας την εστίαση στο μενού καρτέλας και πιέζοντας το κατάλληλο πλήκτρο βέλους\n' + + ' για να μετακινηθείτε κυκλικά στις διαθέσιμες καρτέλες.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/en.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/en.js new file mode 100644 index 0000000..5dd753e --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/en.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.en', +'

Begin keyboard navigation

\n' + + '\n' + + '
\n' + + '
Focus the Menu bar
\n' + + '
Windows or Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Focus the Toolbar
\n' + + '
Windows or Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Focus the footer
\n' + + '
Windows or Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Focus the notification
\n' + + '
Windows or Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Focus a contextual toolbar
\n' + + '
Windows, Linux or macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigation will start at the first UI item, which will be highlighted, or underlined in the case of the first item in\n' + + ' the Footer element path.

\n' + + '\n' + + '

Navigate between UI sections

\n' + + '\n' + + '

To move from one UI section to the next, press Tab.

\n' + + '\n' + + '

To move from one UI section to the previous, press Shift+Tab.

\n' + + '\n' + + '

The Tab order of these UI sections is:

\n' + + '\n' + + '
    \n' + + '
  1. Menu bar
  2. \n' + + '
  3. Each toolbar group
  4. \n' + + '
  5. Sidebar
  6. \n' + + '
  7. Element path in the footer
  8. \n' + + '
  9. Word count toggle button in the footer
  10. \n' + + '
  11. Branding link in the footer
  12. \n' + + '
  13. Editor resize handle in the footer
  14. \n' + + '
\n' + + '\n' + + '

If a UI section is not present, it is skipped.

\n' + + '\n' + + '

If the footer has keyboard navigation focus, and there is no visible sidebar, pressing Shift+Tab\n' + + ' moves focus to the first toolbar group, not the last.

\n' + + '\n' + + '

Navigate within UI sections

\n' + + '\n' + + '

To move from one UI element to the next, press the appropriate Arrow key.

\n' + + '\n' + + '

The Left and Right arrow keys

\n' + + '\n' + + '
    \n' + + '
  • move between menus in the menu bar.
  • \n' + + '
  • open a sub-menu in a menu.
  • \n' + + '
  • move between buttons in a toolbar group.
  • \n' + + '
  • move between items in the footer’s element path.
  • \n' + + '
\n' + + '\n' + + '

The Down and Up arrow keys

\n' + + '\n' + + '
    \n' + + '
  • move between menu items in a menu.
  • \n' + + '
  • move between items in a toolbar pop-up menu.
  • \n' + + '
\n' + + '\n' + + '

Arrow keys cycle within the focused UI section.

\n' + + '\n' + + '

To close an open menu, an open sub-menu, or an open pop-up menu, press the Esc key.

\n' + + '\n' + + '

If the current focus is at the ‘top’ of a particular UI section, pressing the Esc key also exits\n' + + ' keyboard navigation entirely.

\n' + + '\n' + + '

Execute a menu item or toolbar button

\n' + + '\n' + + '

When the desired menu item or toolbar button is highlighted, press Return, Enter,\n' + + ' or the Space bar to execute the item.

\n' + + '\n' + + '

Navigate non-tabbed dialogs

\n' + + '\n' + + '

In non-tabbed dialogs, the first interactive component takes focus when the dialog opens.

\n' + + '\n' + + '

Navigate between interactive dialog components by pressing Tab or Shift+Tab.

\n' + + '\n' + + '

Navigate tabbed dialogs

\n' + + '\n' + + '

In tabbed dialogs, the first button in the tab menu takes focus when the dialog opens.

\n' + + '\n' + + '

Navigate between interactive components of this dialog tab by pressing Tab or\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Switch to another dialog tab by giving the tab menu focus and then pressing the appropriate Arrow\n' + + ' key to cycle through the available tabs.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/es.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/es.js new file mode 100644 index 0000000..e426c2e --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/es.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.es', +'

Iniciar la navegación con el teclado

\n' + + '\n' + + '
\n' + + '
Enfocar la barra de menús
\n' + + '
Windows o Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Enfocar la barra de herramientas
\n' + + '
Windows o Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Enfocar el pie de página
\n' + + '
Windows o Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Enfocar la notificación
\n' + + '
Windows o Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Enfocar una barra de herramientas contextual
\n' + + '
Windows, Linux o macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

La navegación comenzará por el primer elemento de la interfaz de usuario (IU), de tal manera que se resaltará, o bien se subrayará si se trata del primer elemento de\n' + + ' la ruta de elemento del pie de página.

\n' + + '\n' + + '

Navegar entre las secciones de la IU

\n' + + '\n' + + '

Para pasar de una sección de la IU a la siguiente, pulse la tecla Tab.

\n' + + '\n' + + '

Para pasar de una sección de la IU a la anterior, pulse Mayús+Tab.

\n' + + '\n' + + '

El orden de tabulación de estas secciones de la IU es:

\n' + + '\n' + + '
    \n' + + '
  1. Barra de menús
  2. \n' + + '
  3. Cada grupo de barra de herramientas
  4. \n' + + '
  5. Barra lateral
  6. \n' + + '
  7. Ruta del elemento en el pie de página
  8. \n' + + '
  9. Botón de alternancia de recuento de palabras en el pie de página
  10. \n' + + '
  11. Enlace de personalización de marca en el pie de página
  12. \n' + + '
  13. Controlador de cambio de tamaño en el pie de página
  14. \n' + + '
\n' + + '\n' + + '

Si una sección de la IU no está presente, esta se omite.

\n' + + '\n' + + '

Si el pie de página tiene un enfoque de navegación con el teclado y no hay ninguna barra lateral visible, al pulsar Mayús+Tab,\n' + + ' el enfoque se moverá al primer grupo de barra de herramientas, en lugar de al último.

\n' + + '\n' + + '

Navegar dentro de las secciones de la IU

\n' + + '\n' + + '

Para pasar de un elemento de la IU al siguiente, pulse la tecla de flecha correspondiente.

\n' + + '\n' + + '

Las teclas de flecha izquierda y derecha permiten

\n' + + '\n' + + '
    \n' + + '
  • desplazarse entre los menús de la barra de menús.
  • \n' + + '
  • abrir el submenú de un menú.
  • \n' + + '
  • desplazarse entre los botones de un grupo de barra de herramientas.
  • \n' + + '
  • desplazarse entre los elementos de la ruta de elemento del pie de página.
  • \n' + + '
\n' + + '\n' + + '

Las teclas de flecha abajo y arriba permiten

\n' + + '\n' + + '
    \n' + + '
  • desplazarse entre los elementos de menú de un menú.
  • \n' + + '
  • desplazarse entre los elementos de un menú emergente de una barra de herramientas.
  • \n' + + '
\n' + + '\n' + + '

Las teclas de flecha van cambiando dentro de la sección de la IU enfocada.

\n' + + '\n' + + '

Para cerrar un menú, un submenú o un menú emergente que estén abiertos, pulse la tecla Esc.

\n' + + '\n' + + '

Si el enfoque actual se encuentra en la parte superior de una sección de la IU determinada, al pulsar la tecla Esc saldrá\n' + + ' de la navegación con el teclado por completo.

\n' + + '\n' + + '

Ejecutar un elemento de menú o un botón de barra de herramientas

\n' + + '\n' + + '

Si el elemento de menú o el botón de barra de herramientas deseado está resaltado, pulse la tecla Retorno o Entrar,\n' + + ' o la barra espaciadora para ejecutar el elemento.

\n' + + '\n' + + '

Navegar por cuadros de diálogo sin pestañas

\n' + + '\n' + + '

En los cuadros de diálogo sin pestañas, el primer componente interactivo se enfoca al abrirse el cuadro de diálogo.

\n' + + '\n' + + '

Para navegar entre los componentes interactivos del cuadro de diálogo, pulse las teclas Tab o Mayús+Tab.

\n' + + '\n' + + '

Navegar por cuadros de diálogo con pestañas

\n' + + '\n' + + '

En los cuadros de diálogo con pestañas, el primer botón del menú de pestaña se enfoca al abrirse el cuadro de diálogo.

\n' + + '\n' + + '

Para navegar entre componentes interactivos de esta pestaña del cuadro de diálogo, pulse las teclas Tab o\n' + + ' Mayús+Tab.

\n' + + '\n' + + '

Si desea cambiar a otra pestaña del cuadro de diálogo, enfoque el menú de pestañas y, a continuación, pulse la tecla de flecha\n' + + ' correspondiente para moverse por las pestañas disponibles.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/eu.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/eu.js new file mode 100644 index 0000000..c18b940 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/eu.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.eu', +'

Hasi teklatuaren nabigazioa

\n' + + '\n' + + '
\n' + + '
Fokuratu menu-barra
\n' + + '
Windows edo Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokuratu tresna-barra
\n' + + '
Windows edo Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokuratu orri-oina
\n' + + '
Windows edo Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Fokuratu jakinarazpena
\n' + + '
Windows edo Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokuratu testuinguruaren tresna-barra
\n' + + '
Windows, Linux edo macOS: Ktrl+F9
\n' + + '
\n' + + '\n' + + '

Nabigazioa EIko lehen elementuan hasiko da: elementu hori nabarmendu egingo da, edo azpimarratu lehen elementua bada\n' + + ' orri-oineko elementuaren bidea.

\n' + + '\n' + + '

Nabigatu EIko atalen artean

\n' + + '\n' + + '

EIko atal batetik hurrengora mugitzeko, sakatu Tabuladorea.

\n' + + '\n' + + '

EIko atal batetik aurrekora mugitzeko, sakatu Maius+Tabuladorea.

\n' + + '\n' + + '

EIko atal hauen Tabuladorea da:

\n' + + '\n' + + '
    \n' + + '
  1. Menu-barra
  2. \n' + + '
  3. Tresna-barraren talde bakoitza
  4. \n' + + '
  5. Alboko barra
  6. \n' + + '
  7. Orri-oineko elementuaren bidea
  8. \n' + + '
  9. Orri-oneko urrats-kontaketa txandakatzeko botoia
  10. \n' + + '
  11. Orri-oineko marken esteka
  12. \n' + + '
  13. Orri-oineko editorearen tamaina aldatzeko heldulekua
  14. \n' + + '
\n' + + '\n' + + '

EIko atal bat ez badago, saltatu egin da.

\n' + + '\n' + + '

Orri-oinak teklatuaren nabigazioa fokuratuta badago, eta alboko barra ikusgai ez badago, Maius+Tabuladorea sakatuz gero,\n' + + ' fokua tresna-barrako lehen taldera eramaten da, ez azkenera.

\n' + + '\n' + + '

Nabigatu EIko atalen barruan

\n' + + '\n' + + '

EIko elementu batetik hurrengora mugitzeko, sakatu dagokion Gezia tekla.

\n' + + '\n' + + '

Ezkerrera eta Eskuinera gezi-teklak

\n' + + '\n' + + '
    \n' + + '
  • menu-barrako menuen artean mugitzen da.
  • \n' + + '
  • ireki azpimenu bat menuan.
  • \n' + + '
  • mugitu botoi batetik bestera tresna-barren talde batean.
  • \n' + + '
  • mugitu orri-oineko elementuaren bideko elementu batetik bestera.
  • \n' + + '
\n' + + '\n' + + '

Gora eta Behera gezi-teklak

\n' + + '\n' + + '
    \n' + + '
  • mugitu menu bateko menu-elementuen artean.
  • \n' + + '
  • mugitu tresna-barrako menu gainerakor bateko menu-elementuen artean.
  • \n' + + '
\n' + + '\n' + + '

Gezia teklen zikloa nabarmendutako EI atalen barruan.

\n' + + '\n' + + '

Irekitako menu bat ixteko, ireki azpimenua, edo ireki menu gainerakorra, sakatu Ihes tekla.

\n' + + '\n' + + '

Une horretan fokuratzea EIko atal jakin baten "goialdean" badago, Ihes tekla sakatuz gero\n' + + ' teklatuaren nabigaziotik irtengo zara.

\n' + + '\n' + + '

Exekutatu menuko elementu bat edo tresna-barrako botoi bat

\n' + + '\n' + + '

Nahi den menuaren elementua edo tresna-barraren botoia nabarmenduta dagoenean, sakatu Itzuli, Sartu\n' + + ' edo Zuriune-barra elementua exekutatzeko.

\n' + + '\n' + + '

Nabigatu fitxarik gabeko elkarrizketak

\n' + + '\n' + + '

Fitxarik gabeko elkarrizketetan, lehen osagai interaktiboa fokuratzen da elkarrizketa irekitzen denean.

\n' + + '\n' + + '

Nabigatu elkarrizketa interaktiboko osagai batetik bestera Tabuladorea edo Maius+Tabuladorea sakatuta.

\n' + + '\n' + + '

Nabigatu fitxadun elkarrizketak

\n' + + '\n' + + '

Fitxadun elkarrizketetan, fitxa-menuko lehen botoia fokuratzen da elkarrizketa irekitzen denean.

\n' + + '\n' + + '

Nabigatu elkarrizketa-fitxa honen interaktiboko osagai batetik bestera Tabuladorea edo\n' + + ' Maius+Tabuladorea sakatuta.

\n' + + '\n' + + '

Aldatu beste elkarrizketa-fitxa batera fitxa-menua fokuratu eta dagokion Gezia\n' + + ' tekla sakatzeko, erabilgarri dauden fitxa batetik bestera txandakatzeko.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fa.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fa.js new file mode 100644 index 0000000..2a55012 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fa.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.fa', +'

شروع پیمایش صفحه‌کلید

\n' + + '\n' + + '
\n' + + '
تمرکز بر نوار منو
\n' + + '
Windows یا Linux:‎‏: Alt+F9
\n' + + '
‎‏macOS: ⌥F9‎‏
\n' + + '
تمرکز بر نوار ابزار
\n' + + '
Windows یا Linux‎‏: Alt+F10
\n' + + '
‎‏macOS: ⌥F10‎‏
\n' + + '
تمرکز بر پانویس
\n' + + '
Windows یا Linux‎‏: Alt+F11
\n' + + '
‎‏macOS: ⌥F11‎‏
\n' + + '
تمرکز اعلان
\n' + + '
ویندوز یا لینوکس: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
تمرکز بر نوار ابزار بافتاری
\n' + + '
Windows ،Linux یا macOS:‏ Ctrl+F9
\n' + + '
\n' + + '\n' + + '

پیمایش در اولین مورد رابط کاربری شروع می‌شود و درخصوص اولین مورد در\n' + + ' مسیر عنصر پانویس، برجسته یا زیرخط‌دار می‌شود.

\n' + + '\n' + + '

پیمایش بین بخش‌های رابط کاربری

\n' + + '\n' + + '

برای جابجایی از یک بخش رابط کاربری به بخش بعدی، Tab را فشار دهید.

\n' + + '\n' + + '

برای جابجایی از یک بخش رابط کاربری به بخش قبلی، Shift+Tab را فشار دهید.

\n' + + '\n' + + '

ترتیب Tab این بخش‌های رابط کاربری عبارتند از:

\n' + + '\n' + + '
    \n' + + '
  1. نوار منو
  2. \n' + + '
  3. هر گروه نوار ابزار
  4. \n' + + '
  5. نوار کناری
  6. \n' + + '
  7. مسیر عنصر در پانویس
  8. \n' + + '
  9. دکمه تغییر وضعیت تعداد کلمات در پانویس
  10. \n' + + '
  11. پیوند نمانام‌سازی در پانویس
  12. \n' + + '
  13. دسته تغییر اندازه ویرایشگر در پانویس
  14. \n' + + '
\n' + + '\n' + + '

اگر بخشی از رابط کاربری موجود نباشد، رد می‌شود.

\n' + + '\n' + + '

اگر پانویس دارای تمرکز بر پیمایش صفحه‌کلید باشد،‌ و نوار کناری قابل‌مشاهده وجود ندارد، فشردن Shift+Tab\n' + + ' تمرکز را به گروه نوار ابزار اول می‌برد، نه آخر.

\n' + + '\n' + + '

پیمایش در بخش‌های رابط کاربری

\n' + + '\n' + + '

برای جابجایی از یک عنصر رابط کاربری به بعدی، کلید جهت‌نمای مناسب را فشار دهید.

\n' + + '\n' + + '

کلیدهای جهت‌نمای چپ و راست

\n' + + '\n' + + '
    \n' + + '
  • جابجایی بین منوها در نوار منو.
  • \n' + + '
  • باز کردن منوی فرعی در یک منو.
  • \n' + + '
  • جابجایی بین دکمه‌ها در یک گروه نوار ابزار.
  • \n' + + '
  • جابجایی بین موارد در مسیر عنصر پانویس.
  • \n' + + '
\n' + + '\n' + + '

کلیدهای جهت‌نمای پایین و بالا

\n' + + '\n' + + '
    \n' + + '
  • جابجایی بین موارد منو در یک منو.
  • \n' + + '
  • جابجایی بین موارد در یک منوی بازشوی نوار ابزار.
  • \n' + + '
\n' + + '\n' + + '

کلیدهایجهت‌نما در بخش رابط کاربری متمرکز می‌چرخند.

\n' + + '\n' + + '

برای بستن یک منوی باز، یک منوی فرعی باز، یا یک منوی بازشوی باز، کلید Esc را فشار دهید.

\n' + + '\n' + + '

اگر تمرکز فعلی در «بالای» یک بخش رابط کاربری خاص است، فشردن کلید Esc نیز موجب\n' + + ' خروج کامل از پیمایش صفحه‌کلید می‌شود.

\n' + + '\n' + + '

اجرای یک مورد منو یا دکمه نوار ابزار

\n' + + '\n' + + '

وقتی مورد منو یا دکمه نوار ابزار مورد نظر هایلایت شد، دکمه بازگشت، Enter،\n' + + ' یا نوار Space را فشار دهید تا مورد را اجرا کنید.

\n' + + '\n' + + '

پیمایش در کادرهای گفتگوی بدون زبانه

\n' + + '\n' + + '

در کادرهای گفتگوی بدون زبانه، وقتی کادر گفتگو باز می‌شود، اولین جزء تعاملی متمرکز می‌شود.

\n' + + '\n' + + '

با فشردن Tab یا Shift+Tab، بین اجزای کادر گفتگوی تعاملی پیمایش کنید.

\n' + + '\n' + + '

پیمایش کادرهای گفتگوی زبانه‌دار

\n' + + '\n' + + '

در کادرهای گفتگوی زبانه‌دار، وقتی کادر گفتگو باز می‌شود، اولین دکمه در منوی زبانه متمرکز می‌شود.

\n' + + '\n' + + '

با فشردن Tab یا\n' + + ' Shift+Tab، بین اجزای تعاملی این زبانه کادر گفتگو پیمایش کنید.

\n' + + '\n' + + '

با دادن تمرکز به منوی زبانه و سپس فشار دادن کلید جهت‌نمای\n' + + ' مناسب برای چرخش میان زبانه‌های موجود، به زبانه کادر گفتگوی دیگری بروید.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fi.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fi.js new file mode 100644 index 0000000..f01dc91 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fi.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.fi', +'

Näppäimistönavigoinnin aloittaminen

\n' + + '\n' + + '
\n' + + '
Siirrä kohdistus valikkopalkkiin
\n' + + '
Windows tai Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Siirrä kohdistus työkalupalkkiin
\n' + + '
Windows tai Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Siirrä kohdistus alatunnisteeseen
\n' + + '
Windows tai Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Keskitä ilmoitukseen
\n' + + '
Windows ja Linux: Alt + F12
\n' + + '
macOS: ⌥F12
\n' + + '
Siirrä kohdistus kontekstuaaliseen työkalupalkkiin
\n' + + '
Windows, Linux tai macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigointi aloitetaan ensimmäisestä käyttöliittymän kohteesta, joka joko korostetaan tai alleviivataan, jos\n' + + ' kyseessä on Alatunniste-elementin polun ensimmäinen kohde.

\n' + + '\n' + + '

Käyttöliittymän eri osien välillä navigointi

\n' + + '\n' + + '

Paina sarkainnäppäintä siirtyäksesi käyttöliittymän osasta seuraavaan.

\n' + + '\n' + + '

Jos haluat siirtyä edelliseen käyttöliittymän osaan, paina Shift+sarkainnäppäin.

\n' + + '\n' + + '

Sarkainnäppäin siirtää sinua näissä käyttöliittymän osissa tässä järjestyksessä:

\n' + + '\n' + + '
    \n' + + '
  1. Valikkopalkki
  2. \n' + + '
  3. Työkalupalkin ryhmät
  4. \n' + + '
  5. Sivupalkki
  6. \n' + + '
  7. Elementin polku alatunnisteessa
  8. \n' + + '
  9. Sanalaskurin vaihtopainike alatunnisteessa
  10. \n' + + '
  11. Brändäyslinkki alatunnisteessa
  12. \n' + + '
  13. Editorin koon muuttamisen kahva alatunnisteessa
  14. \n' + + '
\n' + + '\n' + + '

Jos jotakin käyttöliittymän osaa ei ole, se ohitetaan.

\n' + + '\n' + + '

Jos kohdistus on siirretty alatunnisteeseen näppäimistönavigoinnilla eikä sivupalkkia ole näkyvissä, Shift+sarkainnäppäin\n' + + ' siirtää kohdistuksen työkalupalkin ensimmäiseen ryhmään, eikä viimeiseen.

\n' + + '\n' + + '

Käyttöliittymän eri osien sisällä navigointi

\n' + + '\n' + + '

Paina nuolinäppäimiä siirtyäksesi käyttöliittymäelementistä seuraavaan.

\n' + + '\n' + + '

Vasen- ja Oikea-nuolinäppäimet

\n' + + '\n' + + '
    \n' + + '
  • siirtävät sinua valikkopalkin valikoiden välillä.
  • \n' + + '
  • avaavat valikon alavalikon.
  • \n' + + '
  • siirtävät sinua työkalupalkin ryhmän painikkeiden välillä.
  • \n' + + '
  • siirtävät sinua kohteiden välillä alatunnisteen elementin polussa.
  • \n' + + '
\n' + + '\n' + + '

Alas- ja Ylös-nuolinäppäimet

\n' + + '\n' + + '
    \n' + + '
  • siirtävät sinua valikon valikkokohteiden välillä.
  • \n' + + '
  • siirtävät sinua työkalupalkin ponnahdusvalikon kohteiden välillä.
  • \n' + + '
\n' + + '\n' + + '

Nuolinäppäimet siirtävät sinua käyttöliittymän korostetun osan sisällä syklissä.

\n' + + '\n' + + '

Paina Esc-näppäintä sulkeaksesi avoimen valikon, avataksesi alavalikon tai avataksesi ponnahdusvalikon.

\n' + + '\n' + + '

Jos kohdistus on käyttöliittymän tietyn osion ylälaidassa, Esc-näppäimen painaminen\n' + + ' poistuu myös näppäimistönavigoinnista kokonaan.

\n' + + '\n' + + '

Suorita valikkokohde tai työkalupalkin painike

\n' + + '\n' + + '

Kun haluamasi valikkokohde tai työkalupalkin painike on korostettuna, paina Return-, Enter-\n' + + ' tai välilyöntinäppäintä suorittaaksesi kohteen.

\n' + + '\n' + + '

Välilehdittömissä valintaikkunoissa navigointi

\n' + + '\n' + + '

Kun välilehdetön valintaikkuna avautuu, kohdistus siirtyy sen ensimmäiseen interaktiiviseen komponenttiin.

\n' + + '\n' + + '

Voit siirtyä valintaikkunan interaktiivisten komponenttien välillä painamalla sarkainnäppäintä tai Shift+sarkainnäppäin.

\n' + + '\n' + + '

Välilehdellisissä valintaikkunoissa navigointi

\n' + + '\n' + + '

Kun välilehdellinen valintaikkuna avautuu, kohdistus siirtyy välilehtivalikon ensimmäiseen painikkeeseen.

\n' + + '\n' + + '

Voit siirtyä valintaikkunan välilehden interaktiivisen komponenttien välillä painamalla sarkainnäppäintä tai\n' + + ' Shift+sarkainnäppäin.

\n' + + '\n' + + '

Voit siirtyä valintaikkunan toiseen välilehteen siirtämällä kohdistuksen välilehtivalikkoon ja painamalla sopivaa nuolinäppäintä\n' + + ' siirtyäksesi käytettävissä olevien välilehtien välillä syklissä.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fr_FR.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fr_FR.js new file mode 100644 index 0000000..3f611e8 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fr_FR.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.fr_FR', +'

Débuter la navigation au clavier

\n' + + '\n' + + '
\n' + + '
Cibler la barre du menu
\n' + + '
Windows ou Linux : Alt+F9
\n' + + '
macOS : ⌥F9
\n' + + "
Cibler la barre d'outils
\n" + + '
Windows ou Linux : Alt+F10
\n' + + '
macOS : ⌥F10
\n' + + '
Cibler le pied de page
\n' + + '
Windows ou Linux : Alt+F11
\n' + + '
macOS : ⌥F11
\n' + + '
Cibler la notification
\n' + + '
Windows ou Linux : Alt+F12
\n' + + '
macOS : ⌥F12
\n' + + "
Cibler une barre d'outils contextuelle
\n" + + '
Windows, Linux ou macOS : Ctrl+F9
\n' + + '
\n' + + '\n' + + "

La navigation débutera sur le premier élément de l'interface utilisateur, qui sera mis en surbrillance ou bien souligné dans le cas du premier élément du\n" + + " chemin d'éléments du pied de page.

\n" + + '\n' + + "

Naviguer entre les sections de l'interface utilisateur

\n" + + '\n' + + "

Pour passer d'une section de l'interface utilisateur à la suivante, appuyez sur Tabulation.

\n" + + '\n' + + "

Pour passer d'une section de l'interface utilisateur à la précédente, appuyez sur Maj+Tabulation.

\n" + + '\n' + + "

L'ordre de Tabulation de ces sections de l'interface utilisateur est le suivant :

\n" + + '\n' + + '
    \n' + + '
  1. Barre du menu
  2. \n' + + "
  3. Chaque groupe de barres d'outils
  4. \n" + + '
  5. Barre latérale
  6. \n' + + "
  7. Chemin d'éléments du pied de page
  8. \n" + + "
  9. Bouton d'activation du compteur de mots dans le pied de page
  10. \n" + + '
  11. Lien de marque dans le pied de page
  12. \n' + + "
  13. Poignée de redimensionnement de l'éditeur dans le pied de page
  14. \n" + + '
\n' + + '\n' + + "

Si une section de l'interface utilisateur n'est pas présente, elle sera ignorée.

\n" + + '\n' + + "

Si le pied de page comporte un ciblage par navigation au clavier et qu'il n'y a aucune barre latérale visible, appuyer sur Maj+Tabulation\n" + + " déplace le ciblage vers le premier groupe de barres d'outils et non le dernier.

\n" + + '\n' + + "

Naviguer au sein des sections de l'interface utilisateur

\n" + + '\n' + + "

Pour passer d'un élément de l'interface utilisateur au suivant, appuyez sur la Flèche appropriée.

\n" + + '\n' + + '

Les touches fléchées Gauche et Droite

\n' + + '\n' + + '
    \n' + + '
  • se déplacent entre les menus de la barre des menus.
  • \n' + + "
  • ouvrent un sous-menu au sein d'un menu.
  • \n" + + "
  • se déplacent entre les boutons d'un groupe de barres d'outils.
  • \n" + + "
  • se déplacent entre les éléments du chemin d'éléments du pied de page.
  • \n" + + '
\n' + + '\n' + + '

Les touches fléchées Bas et Haut

\n' + + '\n' + + '
    \n' + + "
  • se déplacent entre les éléments de menu au sein d'un menu.
  • \n" + + "
  • se déplacent entre les éléments au sein d'un menu contextuel de barre d'outils.
  • \n" + + '
\n' + + '\n' + + "

Les Flèches parcourent la section de l'interface utilisateur ciblée.

\n" + + '\n' + + '

Pour fermer un menu ouvert, un sous-menu ouvert ou un menu contextuel ouvert, appuyez sur Echap.

\n' + + '\n' + + "

Si l'actuel ciblage se trouve en « haut » d'une section spécifique de l'interface utilisateur, appuyer sur Echap permet également de quitter\n" + + ' entièrement la navigation au clavier.

\n' + + '\n' + + "

Exécuter un élément de menu ou un bouton de barre d'outils

\n" + + '\n' + + "

Lorsque l'élément de menu ou le bouton de barre d'outils désiré est mis en surbrillance, appuyez sur la touche Retour arrière, Entrée\n" + + " ou la Barre d'espace pour exécuter l'élément.

\n" + + '\n' + + '

Naviguer au sein de dialogues sans onglets

\n' + + '\n' + + "

Dans les dialogues sans onglets, le premier composant interactif est ciblé lorsque le dialogue s'ouvre.

\n" + + '\n' + + '

Naviguez entre les composants du dialogue interactif en appuyant sur Tabulation ou Maj+Tabulation.

\n' + + '\n' + + '

Naviguer au sein de dialogues avec onglets

\n' + + '\n' + + "

Dans les dialogues avec onglets, le premier bouton du menu de l'onglet est ciblé lorsque le dialogue s'ouvre.

\n" + + '\n' + + '

Naviguez entre les composants interactifs de cet onglet de dialogue en appuyant sur Tabulation ou\n' + + ' Maj+Tabulation.

\n' + + '\n' + + "

Passez à un autre onglet de dialogue en ciblant le menu de l'onglet et en appuyant sur la Flèche\n" + + ' appropriée pour parcourir les onglets disponibles.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/he_IL.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/he_IL.js new file mode 100644 index 0000000..7d6513a --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/he_IL.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.he_IL', +'

התחל ניווט במקלדת

\n' + + '\n' + + '
\n' + + '
התמקד בשורת התפריטים
\n' + + '
Windows או Linux:‏ Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
העבר מיקוד לסרגל הכלים
\n' + + '
Windows או Linux:‏ Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
העבר מיקוד לכותרת התחתונה
\n' + + '
Windows או Linux:‏ Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
העבר מיקוד להודעה
\n' + + '
Windows או Linux:‏ Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
העבר מיקוד לסרגל כלים הקשרי
\n' + + '
Windows‏, Linux או macOS:‏ Ctrl+F9
\n' + + '
\n' + + '\n' + + '

הניווט יתחיל ברכיב הראשון במשך, שיודגש או שיהיה מתחתיו קו תחתון במקרה של הפריט הראשון\n' + + ' הנתיב של רכיב הכותרת התחתונה.

\n' + + '\n' + + '

עבור בין מקטעים במסך

\n' + + '\n' + + '

כדי לעבור בין המקטעים במסך, הקש Tab.

\n' + + '\n' + + '

כדי לעבור למקטע הקודם במסך, הקש Shift+Tab.

\n' + + '\n' + + '

הסדר מבחינת מקש Tab של הרכיבים במסך:

\n' + + '\n' + + '
    \n' + + '
  1. שורת התפריטים
  2. \n' + + '
  3. כל קבוצה בסרגל הכלים
  4. \n' + + '
  5. הסרגל הצידי
  6. \n' + + '
  7. נתיב של רכיב בכותרת התחתונה
  8. \n' + + '
  9. לחצן לספירת מילים בכותרת התחתונה
  10. \n' + + '
  11. קישור של המותג בכותרת התחתונה
  12. \n' + + '
  13. ידית לשינוי גודל עבור העורך בכותרת התחתונה
  14. \n' + + '
\n' + + '\n' + + '

אם רכיב כלשהו במסך לא מופיע, המערכת תדלג עליו.

\n' + + '\n' + + '

אם בכותרת התחתונה יש מיקוד של ניווט במקלדת, ולא מופיע סרגל בצד, יש להקיש Shift+Tab\n' + + ' מעביר את המיקוד לקבוצה הראשונה בסרגל הכלים, לא האחרונה.

\n' + + '\n' + + '

עבור בתוך מקטעים במסך

\n' + + '\n' + + '

כדי לעבור מרכיב אחד לרכיב אחר במסך, הקש על מקש החץ המתאים.

\n' + + '\n' + + '

מקשי החיצים שמאלה וימינה

\n' + + '\n' + + '
    \n' + + '
  • עבור בין תפריטים בשורת התפריטים.
  • \n' + + '
  • פתח תפריט משני בתפריט.
  • \n' + + '
  • עבור בין לחצנים בקבוצה בסרגל הכלים.
  • \n' + + '
  • עבור בין פריטים ברכיב בכותרת התחתונה.
  • \n' + + '
\n' + + '\n' + + '

מקשי החיצים למטה ולמעלה

\n' + + '\n' + + '
    \n' + + '
  • עבור בין פריטים בתפריט.
  • \n' + + '
  • עבור בין פריטים בחלון הקובץ של סרגל הכלים.
  • \n' + + '
\n' + + '\n' + + '

מקשי החצים משתנים בתוך המקטע במסך שעליו נמצא המיקוד.

\n' + + '\n' + + '

כדי לסגור תפריט פתוח, תפריט משני פתוח או חלון קופץ, הקש על Esc.

\n' + + '\n' + + "

אם המיקוד הוא על החלק 'העליון' של מקטע מסוים במסך, הקשה על Esc מביאה גם ליציאה\n" + + ' מהניווט במקלדת לחלוטין.

\n' + + '\n' + + '

הפעל פריט בתפריט או לחצן בסרגל הכלים

\n' + + '\n' + + '

כאשר הפריט הרצוי בתפריט או הלחצן בסרגל הכלים מודגשים, הקש על Return, Enter,\n' + + ' או על מקש הרווח כדי להפעיל את הפריט.

\n' + + '\n' + + '

ניווט בחלונות דו-שיח בלי כרטיסיות

\n' + + '\n' + + '

בחלונות דו-שיח בלי כרטיסיות, הרכיב האינטראקטיבי הראשון מקבל את המיקוד כאשר החלון נפתח.

\n' + + '\n' + + '

עבור בין רכיבים אינטראקטיביים בחלון על ידי הקשה על Tab או Shift+Tab.

\n' + + '\n' + + '

ניווט בחלונות דו-שיח עם כרטיסיות

\n' + + '\n' + + '

בחלונות דו-שיח עם כרטיסיות, הלחצן הראשון בתפריט מקבל את המיקוד כאשר החלון נפתח.

\n' + + '\n' + + '

עבור בין רכיבים אינטראקטיביים בחלון על ידי הקשה על Tab או\n' + + ' Shift+Tab.

\n' + + '\n' + + '

עבור לכרטיסיה אחרת בחלון על ידי העברת המיקוד לתפריט הכרטיסיות והקשה על החץהמתאים\n' + + ' כדי לעבור בין הכרטיסיות הזמינות.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hi.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hi.js new file mode 100644 index 0000000..ef59a5c --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hi.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.hi', +'

कीबोर्ड नेविगेशन शुरू करें

\n' + + '\n' + + '
\n' + + '
मेन्यू बार पर फ़ोकस करें
\n' + + '
Windows या Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
टूलबार पर फ़ोकस करें
\n' + + '
Windows या Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
फ़ुटर पर फ़ोकस करें
\n' + + '
Windows या Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
नोटिफ़िकेशन फ़ोकस
\n' + + '
Windows या Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
प्रासंगिक टूलबार पर फ़ोकस करें
\n' + + '
Windows, Linux या macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

नेविगेशन पहले UI आइटम पर शुरू होगा, जिसे हाइलाइट किया जाएगा या पहले आइटम के मामले में फ़ुटर तत्व पथ में\n' + + ' रेखांकित किया जाएगा।

\n' + + '\n' + + '

UI सेक्शन के बीच नेविगेट करें

\n' + + '\n' + + '

एक UI सेक्शन से दूसरे सेक्शन में जाने के लिए, Tab दबाएं।

\n' + + '\n' + + '

एक UI सेक्शन से पिछले सेक्शन में जाने के लिए, Shift+Tab दबाएं।

\n' + + '\n' + + '

इन UI सेक्शन का Tab क्रम नीचे दिया गया है:

\n' + + '\n' + + '
    \n' + + '
  1. मेन्यू बार
  2. \n' + + '
  3. प्रत्येक टूलबार समूह
  4. \n' + + '
  5. साइडबार
  6. \n' + + '
  7. फ़ुटर में तत्व पथ
  8. \n' + + '
  9. फ़ुटर में शब्द गणना टॉगल बटन
  10. \n' + + '
  11. फ़ुटर में ब्रांडिंग लिंक
  12. \n' + + '
  13. फ़ुटर में संपादक का आकार बदलने का हैंडल
  14. \n' + + '
\n' + + '\n' + + '

अगर कोई UI सेक्शन मौजूद नहीं है, तो उसे छोड़ दिया जाता है।

\n' + + '\n' + + '

अगर फ़ुटर में कीबोर्ड नेविगेशन फ़ोकस है, और कोई दिखा देने वाला साइडबार नहीं है, तो Shift+Tab दबाने से\n' + + ' फ़ोकस पहले टूलबार समूह पर चला जाता है, पिछले पर नहीं।

\n' + + '\n' + + '

UI सेक्शन के भीतर नेविगेट करें

\n' + + '\n' + + '

एक UI तत्व से दूसरे में जाने के लिए उपयुक्त ऐरो कुंजी दबाएं।

\n' + + '\n' + + '

बाएं और दाएं ऐरो कुंजियां

\n' + + '\n' + + '
    \n' + + '
  • मेन्यू बार में मेन्यू के बीच ले जाती हैं।
  • \n' + + '
  • मेन्यू में एक सब-मेन्यू खोलें।
  • \n' + + '
  • टूलबार समूह में बटनों के बीच ले जाएं।
  • \n' + + '
  • फ़ुटर के तत्व पथ में आइटम के बीच ले जाएं।
  • \n' + + '
\n' + + '\n' + + '

नीचे और ऊपर ऐरो कुंजियां

\n' + + '\n' + + '
    \n' + + '
  • मेन्यू में मेन्यू आइटम के बीच ले जाती हैं।
  • \n' + + '
  • टूलबार पॉप-अप मेन्यू में आइटम के बीच ले जाएं।
  • \n' + + '
\n' + + '\n' + + '

फ़ोकस वाले UI सेक्शन के भीतर ऐरो कुंजियां चलाती रहती हैं।

\n' + + '\n' + + '

कोई खुला मेन्यू, कोई खुला सब-मेन्यू या कोई खुला पॉप-अप मेन्यू बंद करने के लिए Esc कुंजी दबाएं।

\n' + + '\n' + + "

अगर मौजूदा फ़ोकस किसी विशेष UI सेक्शन के 'शीर्ष' पर है, तो Esc कुंजी दबाने से भी\n" + + ' कीबोर्ड नेविगेशन पूरी तरह से बाहर हो जाता है।

\n' + + '\n' + + '

मेन्यू आइटम या टूलबार बटन निष्पादित करें

\n' + + '\n' + + '

जब वांछित मेन्यू आइटम या टूलबार बटन हाइलाइट किया जाता है, तो आइटम को निष्पादित करने के लिए Return, Enter,\n' + + ' या Space bar दबाएं।

\n' + + '\n' + + '

गैर-टैब वाले डायलॉग पर नेविगेट करें

\n' + + '\n' + + '

गैर-टैब वाले डायलॉग में, डायलॉग खुलने पर पहला इंटरैक्टिव घटक फ़ोकस लेता है।

\n' + + '\n' + + '

Tab or Shift+Tab दबाकर इंटरैक्टिव डायलॉग घटकों के बीच नेविगेट करें।

\n' + + '\n' + + '

टैब किए गए डायलॉग पर नेविगेट करें

\n' + + '\n' + + '

टैब किए गए डायलॉग में, डायलॉग खुलने पर टैब मेन्यू में पहला बटन फ़ोकस लेता है।

\n' + + '\n' + + '

इस डायलॉग टैब के इंटरैक्टिव घटकों के बीच नेविगेट करने के लिए Tab या\n' + + ' Shift+Tab दबाएं।

\n' + + '\n' + + '

टैब मेन्यू को फ़ोकस देकर और फिर उपलब्ध टैब में के बीच जाने के लिए उपयुक्त ऐरो\n' + + ' कुंजी दबाकर दूसरे डायलॉग टैब पर स्विच करें।

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hr.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hr.js new file mode 100644 index 0000000..1bf35c5 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hr.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.hr', +'

Početak navigacije na tipkovnici

\n' + + '\n' + + '
\n' + + '
Fokusiranje trake izbornika
\n' + + '
Windows ili Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokusiranje alatne trake
\n' + + '
Windows ili Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokusiranje podnožja
\n' + + '
Windows ili Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Fokusiranje obavijesti
\n' + + '
Windows ili Linux: Alt + F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokusiranje kontekstne alatne trake
\n' + + '
Windows, Linux ili macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigacija će započeti kod prve stavke na korisničkom sučelju, koja će biti istaknuta ili podcrtana ako se radi o prvoj stavci u\n' + + ' putu elementa u podnožju.

\n' + + '\n' + + '

Navigacija između dijelova korisničkog sučelja

\n' + + '\n' + + '

Za pomicanje s jednog dijela korisničkog sučelja na drugi pritisnite tabulator.

\n' + + '\n' + + '

Za pomicanje s jednog dijela korisničkog sučelja na prethodni pritisnite Shift + tabulator.

\n' + + '\n' + + '

Ovo je redoslijed pomicanja tabulatora po dijelovima korisničkog sučelja:

\n' + + '\n' + + '
    \n' + + '
  1. Traka izbornika
  2. \n' + + '
  3. Pojedinačne grupe na alatnoj traci
  4. \n' + + '
  5. Bočna traka
  6. \n' + + '
  7. Put elemenata u podnožju
  8. \n' + + '
  9. Gumb za pomicanje po broju riječi u podnožju
  10. \n' + + '
  11. Veza na brand u podnožju
  12. \n' + + '
  13. Značajka za promjenu veličine alata za uređivanje u podnožju
  14. \n' + + '
\n' + + '\n' + + '

Ako neki dio korisničkog sučelja nije naveden, on se preskače.

\n' + + '\n' + + '

Ako u podnožju postoji fokus za navigaciju na tipkovnici, a nema vidljive bočne trake, pritiskom na Shift + tabulator\n' + + ' fokus se prebacuje na prvu skupinu na alatnoj traci, ne na zadnju.

\n' + + '\n' + + '

Navigacija unutar dijelova korisničkog sučelja

\n' + + '\n' + + '

Za pomicanje s jednog elementa korisničkog sučelja na drugi pritisnite tipku s odgovarajućom strelicom.

\n' + + '\n' + + '

Tipke s lijevom i desnom strelicom

\n' + + '\n' + + '
    \n' + + '
  • služe za pomicanje između izbornika na alatnoj traci.
  • \n' + + '
  • otvaraju podizbornik unutar izbornika.
  • \n' + + '
  • služe za pomicanje između gumba unutar skupina na alatnoj traci.
  • \n' + + '
  • služe za pomicanje između stavki na elementu puta u podnožju.
  • \n' + + '
\n' + + '\n' + + '

Tipke s donjom i gornjom strelicom

\n' + + '\n' + + '
    \n' + + '
  • služe za pomicanje između stavki unutar izbornika.
  • \n' + + '
  • služe za pomicanje između stavki na alatnoj traci skočnog izbornika.
  • \n' + + '
\n' + + '\n' + + '

Tipkama strelica kružno se pomičete unutar dijela korisničkog sučelja koji je u fokusu.

\n' + + '\n' + + '

Za zatvaranje otvorenog izbornika, otvorenog podizbornika ili otvorenog skočnog izbornika pritisnite tipku Esc.

\n' + + '\n' + + '

Ako je fokus trenutačno postavljen na vrh pojedinačnog dijela korisničkog sučelja, pritiskom na tipku Esc također\n' + + ' u potpunosti zatvarate navigaciju na tipkovnici.

\n' + + '\n' + + '

Izvršavanje radnji putem stavki izbornika ili gumba na alatnoj traci

\n' + + '\n' + + '

Nakon što se istakne stavka izbornika ili gumb na alatnoj traci s radnjom koju želite izvršiti, pritisnite tipku Return, Enter\n' + + ' ili razmak da biste pokrenuli željenu radnju.

\n' + + '\n' + + '

Navigacija dijaloškim okvirima izvan kartica

\n' + + '\n' + + '

Prilikom otvaranja dijaloških okvira izvan kartica fokus se nalazi na prvoj interaktivnoj komponenti.

\n' + + '\n' + + '

Navigaciju između interaktivnih dijaloških komponenata vršite pritiskom na tabulator ili Shift + tabulator.

\n' + + '\n' + + '

Navigacija dijaloškim okvirima u karticama

\n' + + '\n' + + '

Prilikom otvaranja dijaloških okvira u karticama fokus se nalazi na prvom gumbu u izborniku unutar kartice.

\n' + + '\n' + + '

Navigaciju između interaktivnih komponenata dijaloškog okvira u kartici vršite pritiskom na tabulator ili\n' + + ' Shift + tabulator.

\n' + + '\n' + + '

Na karticu s drugim dijaloškim okvirom možete se prebaciti tako da stavite fokus na izbornik kartice pa pritisnete tipku s odgovarajućom strelicom\n' + + ' za kružno pomicanje između dostupnih kartica.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hu_HU.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hu_HU.js new file mode 100644 index 0000000..5c984bb --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hu_HU.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.hu_HU', +'

Billentyűzetes navigáció indítása

\n' + + '\n' + + '
\n' + + '
Fókusz a menüsávra
\n' + + '
Windows és Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fókusz az eszköztárra
\n' + + '
Windows és Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fókusz a láblécre
\n' + + '
Windows és Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Ráközelítés az értesítésre
\n' + + '
Windows vagy Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fókusz egy környezetfüggő eszköztárra
\n' + + '
Windows, Linux és macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

A navigáció az első felhasználói felületi elemnél kezdődik, amelyet a rendszer kiemel, illetve aláhúz, amennyiben az az első elem\n' + + ' a lábléc elemútvonalán.

\n' + + '\n' + + '

Navigálás a felhasználói felület szakaszai között

\n' + + '\n' + + '

A felhasználói felület következő szakaszára váltáshoz nyomja meg a Tab billentyűt.

\n' + + '\n' + + '

A felhasználói felület előző szakaszára váltáshoz nyomja meg a Shift+Tab billentyűt.

\n' + + '\n' + + '

A Tab billentyűvel a felhasználói felület szakaszai között a következő sorrendben vált:

\n' + + '\n' + + '
    \n' + + '
  1. Menüsáv
  2. \n' + + '
  3. Az egyes eszköztárcsoportok
  4. \n' + + '
  5. Oldalsáv
  6. \n' + + '
  7. Elemútvonal a láblécen
  8. \n' + + '
  9. Szószámátkapcsoló gomb a láblécen
  10. \n' + + '
  11. Márkalink a láblécen
  12. \n' + + '
  13. Szerkesztő átméretezési fogópontja a láblécen
  14. \n' + + '
\n' + + '\n' + + '

Ha a felhasználói felület valamelyik eleme nincs jelen, a rendszer kihagyja.

\n' + + '\n' + + '

Ha a billentyűzetes navigáció fókusza a láblécen van, és nincs látható oldalsáv, a Shift+Tab\n' + + ' billentyűkombináció lenyomásakor az első eszköztárcsoportra ugrik a fókusz, nem az utolsóra.

\n' + + '\n' + + '

Navigálás a felhasználói felület szakaszain belül

\n' + + '\n' + + '

A felhasználói felület következő elemére váltáshoz nyomja meg a megfelelő nyílbillentyűt.

\n' + + '\n' + + '

A bal és a jobb nyílgomb

\n' + + '\n' + + '
    \n' + + '
  • a menüsávban a menük között vált.
  • \n' + + '
  • a menükben megnyit egy almenüt.
  • \n' + + '
  • az eszköztárcsoportban a gombok között vált.
  • \n' + + '
  • a lábléc elemútvonalán az elemek között vált.
  • \n' + + '
\n' + + '\n' + + '

A le és a fel nyílgomb

\n' + + '\n' + + '
    \n' + + '
  • a menükben a menüpontok között vált.
  • \n' + + '
  • az eszköztár előugró menüjében az elemek között vált.
  • \n' + + '
\n' + + '\n' + + '

A nyílbillentyűk lenyomásával körkörösen lépkedhet a fókuszban lévő felhasználói felületi szakasz elemei között.

\n' + + '\n' + + '

A megnyitott menüket, almenüket és előugró menüket az Esc billentyűvel zárhatja be.

\n' + + '\n' + + '

Ha a fókusz az aktuális felületi elem „felső” részén van, az Esc billentyűvel az egész\n' + + ' billentyűzetes navigációból kilép.

\n' + + '\n' + + '

Menüpont vagy eszköztárgomb aktiválása

\n' + + '\n' + + '

Amikor a kívánt menüelem vagy eszköztárgomb van kijelölve, nyomja meg a Return, az Enter\n' + + ' vagy a Szóköz billentyűt az adott elem vagy gomb aktiválásához.

\n' + + '\n' + + '

Navigálás a lapokkal nem rendelkező párbeszédablakokban

\n' + + '\n' + + '

A lapokkal nem rendelkező párbeszédablakokban az első interaktív összetevő kapja a fókuszt, amikor a párbeszédpanel megnyílik.

\n' + + '\n' + + '

A párbeszédpanelek interaktív összetevői között a Tab vagy a Shift+Tab billentyűvel navigálhat.

\n' + + '\n' + + '

Navigálás a lapokkal rendelkező párbeszédablakokban

\n' + + '\n' + + '

A lapokkal rendelkező párbeszédablakokban a lapmenü első gombja kapja a fókuszt, amikor a párbeszédpanel megnyílik.

\n' + + '\n' + + '

A párbeszédpanel e lapjának interaktív összetevői között a Tab vagy\n' + + ' Shift+Tab billentyűvel navigálhat.

\n' + + '\n' + + '

A párbeszédablak másik lapjára úgy léphet, hogy a fókuszt a lapmenüre állítja, majd lenyomja a megfelelő nyílbillentyűt\n' + + ' a rendelkezésre álló lapok közötti lépkedéshez.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/id.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/id.js new file mode 100644 index 0000000..d607dd1 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/id.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.id', +'

Memulai navigasi keyboard

\n' + + '\n' + + '
\n' + + '
Fokus pada bilah Menu
\n' + + '
Windows atau Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokus pada Bilah Alat
\n' + + '
Windows atau Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokus pada footer
\n' + + '
Windows atau Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Fokuskan pemberitahuan
\n' + + '
Windows atau Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokus pada bilah alat kontekstual
\n' + + '
Windows, Linux, atau macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigasi akan dimulai dari item pertama UI, yang akan disorot atau digarisbawahi di\n' + + ' alur elemen Footer.

\n' + + '\n' + + '

Berpindah antar-bagian UI

\n' + + '\n' + + '

Untuk berpindah dari satu bagian UI ke bagian berikutnya, tekan Tab.

\n' + + '\n' + + '

Untuk berpindah dari satu bagian UI ke bagian sebelumnya, tekan Shift+Tab.

\n' + + '\n' + + '

Urutan Tab bagian-bagian UI ini adalah:

\n' + + '\n' + + '
    \n' + + '
  1. Bilah menu
  2. \n' + + '
  3. Tiap grup bilah alat
  4. \n' + + '
  5. Bilah sisi
  6. \n' + + '
  7. Alur elemen di footer
  8. \n' + + '
  9. Tombol aktifkan/nonaktifkan jumlah kata di footer
  10. \n' + + '
  11. Tautan merek di footer
  12. \n' + + '
  13. Pengatur pengubahan ukuran editor di footer
  14. \n' + + '
\n' + + '\n' + + '

Jika suatu bagian UI tidak ada, bagian tersebut dilewati.

\n' + + '\n' + + '

Jika fokus navigasi keyboard ada pada footer, tetapi tidak ada bilah sisi yang terlihat, menekan Shift+Tab\n' + + ' akan memindahkan fokus ke grup bilah alat pertama, bukan yang terakhir.

\n' + + '\n' + + '

Berpindah di dalam bagian-bagian UI

\n' + + '\n' + + '

Untuk berpindah dari satu elemen UI ke elemen berikutnya, tekan tombol Panah yang sesuai.

\n' + + '\n' + + '

Tombol panah Kiri dan Kanan untuk

\n' + + '\n' + + '
    \n' + + '
  • berpindah-pindah antar-menu di dalam bilah menu.
  • \n' + + '
  • membuka sub-menu di dalam menu.
  • \n' + + '
  • berpindah-pindah antar-tombol di dalam grup bilah alat.
  • \n' + + '
  • berpindah-pindah antar-item di dalam alur elemen footer.
  • \n' + + '
\n' + + '\n' + + '

Tombol panah Bawah dan Atas untuk

\n' + + '\n' + + '
    \n' + + '
  • berpindah-pindah antar-item menu di dalam menu.
  • \n' + + '
  • berpindah-pindah antar-item di dalam menu pop-up bilah alat.
  • \n' + + '
\n' + + '\n' + + '

Tombol Panah hanya bergerak di dalam bagian UI yang difokuskan.

\n' + + '\n' + + '

Untuk menutup menu, sub-menu, atau menu pop-up yang terbuka, tekan tombol Esc.

\n' + + '\n' + + '

Jika fokus sedang berada di ‘atas’ bagian UI tertentu, menekan tombol Esc juga dapat mengeluarkan fokus\n' + + ' dari seluruh navigasi keyboard.

\n' + + '\n' + + '

Menjalankan item menu atau tombol bilah alat

\n' + + '\n' + + '

Jika item menu atau tombol bilah alat yang diinginkan tersorot, tekan Return, Enter,\n' + + ' atau Spasi untuk menjalankan item.

\n' + + '\n' + + '

Berpindah dalam dialog tanpa tab

\n' + + '\n' + + '

Dalam dialog tanpa tab, fokus diarahkan pada komponen interaktif pertama saat dialog terbuka.

\n' + + '\n' + + '

Berpindah di antara komponen dalam dialog interaktif dengan menekan Tab atau Shift+Tab.

\n' + + '\n' + + '

Berpindah dalam dialog dengan tab

\n' + + '\n' + + '

Dalam dialog yang memiliki tab, fokus diarahkan pada tombol pertama di dalam menu saat dialog terbuka.

\n' + + '\n' + + '

Berpindah di antara komponen-komponen interaktif pada tab dialog ini dengan menekan Tab atau\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Beralih ke tab dialog lain dengan mengarahkan fokus pada menu tab lalu tekan tombol Panah\n' + + ' yang sesuai untuk berpindah ke berbagai tab yang tersedia.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/it.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/it.js new file mode 100644 index 0000000..3a791c9 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/it.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.it', +'

Iniziare la navigazione tramite tastiera

\n' + + '\n' + + '
\n' + + '
Impostare lo stato attivo per la barra dei menu
\n' + + '
Windows o Linux: ALT+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Impostare lo stato attivo per la barra degli strumenti
\n' + + '
Windows o Linux: ALT+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Impostare lo stato attivo per il piè di pagina
\n' + + '
Windows o Linux: ALT+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Metti a fuoco la notifica
\n' + + '
Windows o Linux: ALT+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Impostare lo stato attivo per la barra degli strumenti contestuale
\n' + + '
Windows, Linux o macOS: CTRL+F9
\n' + + '
\n' + + '\n' + + "

La navigazione inizierà dalla prima voce dell'interfaccia utente, che sarà evidenziata o sottolineata nel caso della prima voce\n" + + " nel percorso dell'elemento del piè di pagina.

\n" + + '\n' + + "

Navigare tra le sezioni dell'interfaccia utente

\n" + + '\n' + + "

Per passare da una sezione dell'interfaccia utente alla successiva, premere TAB.

\n" + + '\n' + + "

Per passare da una sezione dell'interfaccia utente alla precedente, premere MAIUSC+TAB.

\n" + + '\n' + + "

L'ordine di tabulazione di queste sezioni dell'interfaccia utente è:

\n" + + '\n' + + '
    \n' + + '
  1. Barra dei menu
  2. \n' + + '
  3. Ogni gruppo di barre degli strumenti
  4. \n' + + '
  5. Barra laterale
  6. \n' + + "
  7. Percorso dell'elemento nel piè di pagina
  8. \n" + + '
  9. Pulsante di attivazione/disattivazione del conteggio delle parole nel piè di pagina
  10. \n' + + '
  11. Collegamento al marchio nel piè di pagina
  12. \n' + + "
  13. Quadratino di ridimensionamento dell'editor nel piè di pagina
  14. \n" + + '
\n' + + '\n' + + "

Se una sezione dell'interfaccia utente non è presente, viene saltata.

\n" + + '\n' + + '

Se il piè di pagina ha lo stato attivo per la navigazione tramite tastiera e non è presente alcuna barra laterale visibile, premendo MAIUSC+TAB\n' + + " si sposta lo stato attivo sul primo gruppo di barre degli strumenti, non sull'ultimo.

\n" + + '\n' + + "

Navigare all'interno delle sezioni dell'interfaccia utente

\n" + + '\n' + + "

Per passare da un elemento dell'interfaccia utente al successivo, premere il tasto freccia appropriato.

\n" + + '\n' + + '

I tasti freccia Sinistra e Destra

\n' + + '\n' + + '
    \n' + + '
  • consentono di spostarsi tra i menu della barra dei menu.
  • \n' + + '
  • aprono un sottomenu in un menu.
  • \n' + + '
  • consentono di spostarsi tra i pulsanti di un gruppo di barre degli strumenti.
  • \n' + + "
  • consentono di spostarsi tra le voci nel percorso dell'elemento del piè di pagina.
  • \n" + + '
\n' + + '\n' + + '

I tasti freccia Giù e Su

\n' + + '\n' + + '
    \n' + + '
  • consentono di spostarsi tra le voci di un menu.
  • \n' + + '
  • consentono di spostarsi tra le voci di un menu a comparsa della barra degli strumenti.
  • \n' + + '
\n' + + '\n' + + "

I tasti freccia consentono di spostarsi all'interno della sezione dell'interfaccia utente con stato attivo.

\n" + + '\n' + + '

Per chiudere un menu aperto, un sottomenu aperto o un menu a comparsa aperto, premere il tasto ESC.

\n' + + '\n' + + "

Se lo stato attivo corrente si trova nella parte superiore di una particolare sezione dell'interfaccia utente, premendo il tasto ESC si esce\n" + + ' completamente dalla navigazione tramite tastiera.

\n' + + '\n' + + '

Eseguire una voce di menu o un pulsante della barra degli strumenti

\n' + + '\n' + + '

Quando la voce di menu o il pulsante della barra degli strumenti desiderati sono evidenziati, premere il tasto diritorno a capo, il tasto Invio\n' + + ' o la barra spaziatrice per eseguirli.

\n' + + '\n' + + '

Navigare nelle finestre di dialogo non a schede

\n' + + '\n' + + "

Nelle finestre di dialogo non a schede, all'apertura della finestra di dialogo diventa attivo il primo componente interattivo.

\n" + + '\n' + + '

Per spostarsi tra i componenti interattivi della finestra di dialogo, premere TAB o MAIUSC+TAB.

\n' + + '\n' + + '

Navigare nelle finestre di dialogo a schede

\n' + + '\n' + + "

Nelle finestre di dialogo a schede, all'apertura della finestra di dialogo diventa attivo il primo pulsante del menu della scheda.

\n" + + '\n' + + '

Per spostarsi tra i componenti interattivi di questa scheda della finestra di dialogo, premere TAB o\n' + + ' MAIUSC+TAB.

\n' + + '\n' + + "

Per passare a un'altra scheda della finestra di dialogo, attivare il menu della scheda e premere il tasto freccia\n" + + ' appropriato per scorrere le schede disponibili.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ja.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ja.js new file mode 100644 index 0000000..26872db --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ja.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ja', +'

キーボード ナビゲーションの開始

\n' + + '\n' + + '
\n' + + '
メニュー バーをフォーカス
\n' + + '
Windows または Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
ツール バーをフォーカス
\n' + + '
Windows または Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
フッターをフォーカス
\n' + + '
Windows または Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
通知にフォーカス
\n' + + '
Windows または Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
コンテキスト ツール バーをフォーカス
\n' + + '
Windows、Linux または macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

ナビゲーションは最初の UI 項目から開始され、強調表示されるか、フッターの要素パスにある最初の項目の場合は\n' + + ' 下線が引かれます。

\n' + + '\n' + + '

UI セクション間の移動

\n' + + '\n' + + '

次の UI セクションに移動するには、Tab を押します。

\n' + + '\n' + + '

前の UI セクションに移動するには、Shift+Tab を押します。

\n' + + '\n' + + '

これらの UI セクションの Tab の順序:

\n' + + '\n' + + '
    \n' + + '
  1. メニュー バー
  2. \n' + + '
  3. 各ツール バー グループ
  4. \n' + + '
  5. サイド バー
  6. \n' + + '
  7. フッターの要素パス
  8. \n' + + '
  9. フッターの単語数切り替えボタン
  10. \n' + + '
  11. フッターのブランド リンク
  12. \n' + + '
  13. フッターのエディター サイズ変更ハンドル
  14. \n' + + '
\n' + + '\n' + + '

UI セクションが存在しない場合は、スキップされます。

\n' + + '\n' + + '

フッターにキーボード ナビゲーション フォーカスがあり、表示可能なサイド バーがない場合、Shift+Tab を押すと、\n' + + ' フォーカスが最後ではなく最初のツール バー グループに移動します。

\n' + + '\n' + + '

UI セクション内の移動

\n' + + '\n' + + '

次の UI 要素に移動するには、適切な矢印キーを押します。

\n' + + '\n' + + '

左矢印右矢印のキー

\n' + + '\n' + + '
    \n' + + '
  • メニュー バーのメニュー間で移動します。
  • \n' + + '
  • メニュー内のサブメニューを開きます。
  • \n' + + '
  • ツール バー グループのボタン間で移動します。
  • \n' + + '
  • フッターの要素パスの項目間で移動します。
  • \n' + + '
\n' + + '\n' + + '

下矢印上矢印のキー

\n' + + '\n' + + '
    \n' + + '
  • メニュー内のメニュー項目間で移動します。
  • \n' + + '
  • ツール バー ポップアップ メニュー内のメニュー項目間で移動します。
  • \n' + + '
\n' + + '\n' + + '

矢印キーで、フォーカスされた UI セクション内で循環します。

\n' + + '\n' + + '

開いたメニュー、開いたサブメニュー、開いたポップアップ メニューを閉じるには、Esc キーを押します。

\n' + + '\n' + + '

現在のフォーカスが特定の UI セクションの「一番上」にある場合、Esc キーを押すと\n' + + ' キーボード ナビゲーションも完全に閉じられます。

\n' + + '\n' + + '

メニュー項目またはツール バー ボタンの実行

\n' + + '\n' + + '

目的のメニュー項目やツール バー ボタンが強調表示されている場合、リターンEnter、\n' + + ' またはスペース キーを押して項目を実行します。

\n' + + '\n' + + '

タブのないダイアログの移動

\n' + + '\n' + + '

タブのないダイアログでは、ダイアログが開くと最初の対話型コンポーネントがフォーカスされます。

\n' + + '\n' + + '

Tab または Shift+Tab を押して、対話型ダイアログ コンポーネント間で移動します。

\n' + + '\n' + + '

タブ付きダイアログの移動

\n' + + '\n' + + '

タブ付きダイアログでは、ダイアログが開くとタブ メニューの最初のボタンがフォーカスされます。

\n' + + '\n' + + '

Tab または\n' + + ' Shift+Tab を押して、このダイアログ タブの対話型コンポーネント間で移動します。

\n' + + '\n' + + '

タブ メニューをフォーカスしてから適切な矢印キーを押して表示可能なタブを循環して、\n' + + ' 別のダイアログに切り替えます。

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/kk.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/kk.js new file mode 100644 index 0000000..e31532f --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/kk.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.kk', +'

Пернетақта навигациясын бастау

\n' + + '\n' + + '
\n' + + '
Мәзір жолағын фокустау
\n' + + '
Windows немесе Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Құралдар тақтасын фокустау
\n' + + '
Windows немесе Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Төменгі деректемені фокустау
\n' + + '
Windows немесе Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Хабарландыруды белгілеу
\n' + + '
Windows немесе Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Мәтінмәндік құралдар тақтасын фокустау
\n' + + '
Windows, Linux немесе macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Навигация бөлектелетін немесе Төменгі деректеме элементінің жолындағы бірінші элемент жағдайында асты сызылатын\n' + + ' бірінші ПИ элементінен басталады.

\n' + + '\n' + + '

ПИ бөлімдері арасында навигациялау

\n' + + '\n' + + '

Бір ПИ бөлімінен келесісіне өту үшін Tab пернесін басыңыз.

\n' + + '\n' + + '

Бір ПИ бөлімінен алдыңғысына өту үшін Shift+Tab пернесін басыңыз.

\n' + + '\n' + + '

Осы ПИ бөлімдерінің Tab реті:

\n' + + '\n' + + '
    \n' + + '
  1. Мәзір жолағы
  2. \n' + + '
  3. Әрбір құралдар тақтасы тобы
  4. \n' + + '
  5. Бүйірлік жолақ
  6. \n' + + '
  7. Төменгі деректемедегі элемент жолы
  8. \n' + + '
  9. Төменгі деректемедегі сөздер санын ауыстыру түймесі
  10. \n' + + '
  11. Төменгі деректемедегі брендингтік сілтеме
  12. \n' + + '
  13. Төменгі деректемедегі редактор өлшемін өзгерту тұтқасы
  14. \n' + + '
\n' + + '\n' + + '

ПИ бөлімі көрсетілмесе, ол өткізіп жіберіледі.

\n' + + '\n' + + '

Төменгі деректемеде пернетақта навигациясының фокусы болса және бүйірлік жолақ көрінбесе, Shift+Tab тіркесімін басу әрекеті\n' + + ' фокусты соңғысы емес, бірінші құралдар тақтасы тобына жылжытады.

\n' + + '\n' + + '

ПИ бөлімдерінде навигациялау

\n' + + '\n' + + '

Бір ПИ элементінен келесісіне өту үшін Arrow (Көрсеткі) пернесін басыңыз.

\n' + + '\n' + + '

Left (Сол жақ) және Right (Оң жақ) көрсеткі пернелері

\n' + + '\n' + + '
    \n' + + '
  • мәзір жолағындағы мәзірлер арасында жылжыту.
  • \n' + + '
  • мәзірде ішкі мәзірді ашу.
  • \n' + + '
  • құралдар тақтасы тобындағы түймелер арасында жылжыту.
  • \n' + + '
  • төменгі деректеме элементінің жолындағы элементтер арасында жылжыту.
  • \n' + + '
\n' + + '\n' + + '

Down (Төмен) және Up (Жоғары) көрсеткі пернелері

\n' + + '\n' + + '
    \n' + + '
  • мәзірдегі мәзір элементтері арасында жылжыту.
  • \n' + + '
  • құралдар тақтасының ашылмалы мәзіріндегі мәзір элементтері арасында жылжыту.
  • \n' + + '
\n' + + '\n' + + '

Фокусталған ПИ бөліміндегі Arrow (Көрсеткі) пернелерінің циклі.

\n' + + '\n' + + '

Ашық мәзірді жабу үшін ішкі мәзірді ашып немесе ашылмалы мәзірді ашып, Esc пернесін басыңыз.

\n' + + '\n' + + '

Ағымдағы фокус белгілі бір ПИ бөлімінің «үстінде» болса, Esc пернесін басу әрекеті пернетақта\n' + + ' навигациясын толығымен жабады.

\n' + + '\n' + + '

Мәзір элементін немесе құралдар тақтасы түймесін орындау

\n' + + '\n' + + '

Қажетті мәзір элементі немесе құралдар тақтасы түймесі бөлектелген кезде, элементті орындау үшін Return (Қайтару), Enter (Енгізу)\n' + + ' немесе Space bar (Бос орын) пернесін басыңыз.

\n' + + '\n' + + '

Белгіленбеген диалог терезелерін навигациялау

\n' + + '\n' + + '

Белгіленбеген диалог терезелерінде диалог терезесі ашылған кезде бірінші интерактивті құрамдас фокусталады.

\n' + + '\n' + + '

Tab немесе Shift+Tab пернесін басу арқылы интерактивті диалог терезесінің құрамдастары арасында навигациялаңыз.

\n' + + '\n' + + '

Белгіленген диалог терезелерін навигациялау

\n' + + '\n' + + '

Белгіленген диалог терезелерінде диалог терезесі ашылған кезде қойынды мәзіріндегі бірінші түйме фокусталады.

\n' + + '\n' + + '

Tab немесе\n' + + ' Shift+Tab пернесін басу арқылы осы диалог терезесі қойындысының интерактивті құрамдастары арасында навигациялаңыз.

\n' + + '\n' + + '

Қойынды мәзірінің фокусын беру арқылы басқа диалог терезесінің қойындысына ауысып, тиісті Arrow (Көрсеткі)\n' + + ' пернесін басу арқылы қолжетімді қойындылар арасында айналдыруға болады.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ko_KR.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ko_KR.js new file mode 100644 index 0000000..e7c8e7f --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ko_KR.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ko_KR', +'

키보드 탐색 시작

\n' + + '\n' + + '
\n' + + '
메뉴 모음 포커스 표시
\n' + + '
Windows 또는 Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
도구 모음 포커스 표시
\n' + + '
Windows 또는 Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
푸터 포커스 표시
\n' + + '
Windows 또는 Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
알림 포커스
\n' + + '
Windows 또는 Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
컨텍스트 도구 모음에 포커스 표시
\n' + + '
Windows, Linux 또는 macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

첫 번째 UI 항목에서 탐색이 시작되며, 이때 첫 번째 항목이 강조 표시되거나 푸터 요소 경로에 있는\n' + + ' 경우 밑줄 표시됩니다.

\n' + + '\n' + + '

UI 섹션 간 탐색

\n' + + '\n' + + '

한 UI 섹션에서 다음 UI 섹션으로 이동하려면 Tab(탭)을 누릅니다.

\n' + + '\n' + + '

한 UI 섹션에서 이전 UI 섹션으로 돌아가려면 Shift+Tab(시프트+탭)을 누릅니다.

\n' + + '\n' + + '

이 UI 섹션의 Tab(탭) 순서는 다음과 같습니다.

\n' + + '\n' + + '
    \n' + + '
  1. 메뉴 바
  2. \n' + + '
  3. 각 도구 모음 그룹
  4. \n' + + '
  5. 사이드바
  6. \n' + + '
  7. 푸터의 요소 경로
  8. \n' + + '
  9. 푸터의 단어 수 토글 버튼
  10. \n' + + '
  11. 푸터의 브랜딩 링크
  12. \n' + + '
  13. 푸터의 에디터 크기 변경 핸들
  14. \n' + + '
\n' + + '\n' + + '

UI 섹션이 없는 경우 건너뛰기합니다.

\n' + + '\n' + + '

푸터에 키보드 탐색 포커스가 있고 사이드바는 보이지 않는 경우 Shift+Tab(시프트+탭)을 누르면\n' + + ' 포커스 표시가 마지막이 아닌 첫 번째 도구 모음 그룹으로 이동합니다.

\n' + + '\n' + + '

UI 섹션 내 탐색

\n' + + '\n' + + '

한 UI 요소에서 다음 UI 요소로 이동하려면 적절한 화살표 키를 누릅니다.

\n' + + '\n' + + '

왼쪽오른쪽 화살표 키의 용도:

\n' + + '\n' + + '
    \n' + + '
  • 메뉴 모음에서 메뉴 항목 사이를 이동합니다.
  • \n' + + '
  • 메뉴에서 하위 메뉴를 엽니다.
  • \n' + + '
  • 도구 모음 그룹에서 버튼 사이를 이동합니다.
  • \n' + + '
  • 푸터의 요소 경로에서 항목 간에 이동합니다.
  • \n' + + '
\n' + + '\n' + + '

아래 화살표 키의 용도:

\n' + + '\n' + + '
    \n' + + '
  • 메뉴에서 메뉴 항목 사이를 이동합니다.
  • \n' + + '
  • 도구 모음 팝업 메뉴에서 메뉴 항목 사이를 이동합니다.
  • \n' + + '
\n' + + '\n' + + '

화살표 키는 포커스 표시 UI 섹션 내에서 순환됩니다.

\n' + + '\n' + + '

열려 있는 메뉴, 열려 있는 하위 메뉴 또는 열려 있는 팝업 메뉴를 닫으려면 Esc 키를 누릅니다.

\n' + + '\n' + + "

현재 포커스 표시가 특정 UI 섹션 '상단'에 있는 경우 이때도 Esc 키를 누르면\n" + + ' 키보드 탐색이 완전히 종료됩니다.

\n' + + '\n' + + '

메뉴 항목 또는 도구 모음 버튼 실행

\n' + + '\n' + + '

원하는 메뉴 항목 또는 도구 모음 버튼이 강조 표시되어 있을 때 Return(리턴), Enter(엔터),\n' + + ' 또는 Space bar(스페이스바)를 눌러 해당 항목을 실행합니다.

\n' + + '\n' + + '

탭이 없는 대화 탐색

\n' + + '\n' + + '

탭이 없는 대화의 경우, 첫 번째 대화형 요소가 포커스 표시된 상태로 대화가 열립니다.

\n' + + '\n' + + '

대화형 요소들 사이를 이동할 때는 Tab(탭) 또는 Shift+Tab(시프트+탭)을 누릅니다.

\n' + + '\n' + + '

탭이 있는 대화 탐색

\n' + + '\n' + + '

탭이 있는 대화의 경우, 탭 메뉴에서 첫 번째 버튼이 포커스 표시된 상태로 대화가 열립니다.

\n' + + '\n' + + '

이 대화 탭의 대화형 요소들 사이를 이동할 때는 Tab(탭) 또는\n' + + ' Shift+Tab(시프트+탭)을 누릅니다.

\n' + + '\n' + + '

다른 대화 탭으로 이동하려면 탭 메뉴를 포커스 표시한 다음 적절한 화살표\n' + + ' 키를 눌러 사용 가능한 탭들을 지나 원하는 탭으로 이동합니다.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ms.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ms.js new file mode 100644 index 0000000..2c047bb --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ms.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ms', +'

Mulakan navigasi papan kekunci

\n' + + '\n' + + '
\n' + + '
Fokus bar Menu
\n' + + '
Windows atau Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokus Bar Alat
\n' + + '
Windows atau Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokus pengaki
\n' + + '
Windows atau Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Tumpu kepada pemberitahuan
\n' + + '
Windows atau Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokus bar alat kontekstual
\n' + + '
Windows, Linux atau macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigasi akan bermula pada item UI pertama, yang akan diserlahkan atau digaris bawah dalam saiz item pertama dalam\n' + + ' laluan elemen Pengaki.

\n' + + '\n' + + '

Navigasi antara bahagian UI

\n' + + '\n' + + '

Untuk bergerak dari satu bahagian UI ke yang seterusnya, tekan Tab.

\n' + + '\n' + + '

Untuk bergerak dari satu bahagian UI ke yang sebelumnya, tekan Shift+Tab.

\n' + + '\n' + + '

Tertib Tab bahagian UI ini ialah:

\n' + + '\n' + + '
    \n' + + '
  1. Bar menu
  2. \n' + + '
  3. Setiap kumpulan bar alat
  4. \n' + + '
  5. Bar sisi
  6. \n' + + '
  7. Laluan elemen dalam pengaki
  8. \n' + + '
  9. Butang togol kiraan perkataan dalam pengaki
  10. \n' + + '
  11. Pautan penjenamaan dalam pengaki
  12. \n' + + '
  13. Pemegang saiz semula editor dalam pengaki
  14. \n' + + '
\n' + + '\n' + + '

Jika bahagian UI tidak wujud, ia dilangkau.

\n' + + '\n' + + '

Jika pengaki mempunyai fokus navigasi papan kekunci dan tiada bar sisi kelihatan, menekan Shift+Tab\n' + + ' akan mengalihkan fokus ke kumpulan bar alat pertama, bukannya yang terakhir.

\n' + + '\n' + + '

Navigasi dalam bahagian UI

\n' + + '\n' + + '

Untuk bergerak dari satu elemen UI ke yang seterusnya, tekan kekunci Anak Panah yang bersesuaian.

\n' + + '\n' + + '

Kekunci anak panah Kiri dan Kanan

\n' + + '\n' + + '
    \n' + + '
  • bergerak antara menu dalam bar menu.
  • \n' + + '
  • membukan submenu dalam menu.
  • \n' + + '
  • bergerak antara butang dalam kumpulan bar alat.
  • \n' + + '
  • Laluan elemen dalam pengaki.
  • \n' + + '
\n' + + '\n' + + '

Kekunci anak panah Bawah dan Atas

\n' + + '\n' + + '
    \n' + + '
  • bergerak antara item menu dalam menu.
  • \n' + + '
  • bergerak antara item dalam menu timbul bar alat.
  • \n' + + '
\n' + + '\n' + + '

Kekunci Anak Panah berkitar dalam bahagian UI difokuskan.

\n' + + '\n' + + '

Untuk menutup menu buka, submenu terbuka atau menu timbul terbuka, tekan kekunci Esc.

\n' + + '\n' + + "

Jika fokus semasa berada di bahagian 'atas' bahagian UI tertentu, menekan kekunci Esc juga akan keluar daripada\n" + + ' navigasi papan kekunci sepenuhnya.

\n' + + '\n' + + '

Laksanakan item menu atau butang bar alat

\n' + + '\n' + + '

Apabila item menu atau butang bar alat yang diinginkan diserlahkan, tekan Return, Enter,\n' + + ' atau bar Space untuk melaksanakan item.

\n' + + '\n' + + '

Navigasi ke dialog tidak bertab

\n' + + '\n' + + '

Dalam dialog tidak bertab, komponen interaksi pertama difokuskan apabila dialog dibuka.

\n' + + '\n' + + '

Navigasi antara komponen dialog interaktif dengan menekan Tab atau Shift+Tab.

\n' + + '\n' + + '

Navigasi ke dialog bertab

\n' + + '\n' + + '

Dalam dialog bertab, butang pertama dalam menu tab difokuskan apabila dialog dibuka.

\n' + + '\n' + + '

Navigasi antara komponen interaktif tab dialog ini dengan menekan Tab atau\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Tukar kepada tab dialog lain dengan memfokuskan menu tab, kemudian menekan kekunci Anak Panah yang bersesuaian\n' + + ' untuk berkitar menerusi tab yang tersedia.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nb_NO.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nb_NO.js new file mode 100644 index 0000000..071e3f5 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nb_NO.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.nb_NO', +'

Starte tastaturnavigering

\n' + + '\n' + + '
\n' + + '
Utheve menylinjen
\n' + + '
Windows eller Linux: Alt + F9
\n' + + '
macOS: ⌥F9
\n' + + '
Utheve verktøylinjen
\n' + + '
Windows eller Linux: Alt + F10
\n' + + '
macOS: ⌥F10
\n' + + '
Utheve bunnteksten
\n' + + '
Windows eller Linux: Alt + F11
\n' + + '
macOS: ⌥F11
\n' + + '
Fokuser på varselet
\n' + + '
Windows eller Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Utheve en kontekstuell verktøylinje
\n' + + '
Windows, Linux eller macOS: Ctrl + F9
\n' + + '
\n' + + '\n' + + '

Navigeringen starter ved det første grensesnittelementet, som utheves, eller understrekes når det gjelder det første elementet i\n' + + ' elementstien i bunnteksten.

\n' + + '\n' + + '

Navigere mellom grensesnittdeler

\n' + + '\n' + + '

Du kan bevege deg fra én grensesnittdel til den neste ved å trykke på tabulatortasten.

\n' + + '\n' + + '

Du kan bevege deg fra én grensesnittdel til den forrige ved å trykke på Shift + tabulatortasten.

\n' + + '\n' + + '

Rekkefølgen til tabulatortasten gjennom grensesnittdelene er:

\n' + + '\n' + + '
    \n' + + '
  1. Menylinjen
  2. \n' + + '
  3. Hver gruppe på verktøylinjen
  4. \n' + + '
  5. Sidestolpen
  6. \n' + + '
  7. Elementstien i bunnteksten
  8. \n' + + '
  9. Veksleknappen for ordantall i bunnteksten
  10. \n' + + '
  11. Merkelenken i bunnteksten
  12. \n' + + '
  13. Skaleringshåndtaket for redigeringsprogrammet i bunnteksten
  14. \n' + + '
\n' + + '\n' + + '

Hvis en grensesnittdel ikke er til stede, blir den hoppet over.

\n' + + '\n' + + '

Hvis tastaturnavigeringen har uthevet bunnteksten og det ikke finnes en synlig sidestolpe, kan du trykke på Shift + tabulatortasten\n' + + ' for å flytte fokuset til den første gruppen på verktøylinjen i stedet for den siste.

\n' + + '\n' + + '

Navigere innenfor grensesnittdeler

\n' + + '\n' + + '

Du kan bevege deg fra ett grensesnittelement til det neste ved å trykke på den aktuelle piltasten.

\n' + + '\n' + + '

De venstre og høyre piltastene

\n' + + '\n' + + '
    \n' + + '
  • beveger deg mellom menyer på menylinjen.
  • \n' + + '
  • åpner en undermeny i en meny.
  • \n' + + '
  • beveger deg mellom knapper i en gruppe på verktøylinjen.
  • \n' + + '
  • beveger deg mellom elementer i elementstien i bunnteksten.
  • \n' + + '
\n' + + '\n' + + '

Ned- og opp-piltastene

\n' + + '\n' + + '
    \n' + + '
  • beveger deg mellom menyelementer i en meny.
  • \n' + + '
  • beveger deg mellom elementer i en hurtigmeny på verktøylinjen.
  • \n' + + '
\n' + + '\n' + + '

Med piltastene kan du bevege deg innenfor den uthevede grensesnittdelen.

\n' + + '\n' + + '

Du kan lukke en åpen meny, en åpen undermeny eller en åpen hurtigmeny ved å klikke på Esc-tasten.

\n' + + '\n' + + '

Hvis det øverste nivået i en grensesnittdel er uthevet, kan du ved å trykke på Esc også avslutte\n' + + ' tastaturnavigeringen helt.

\n' + + '\n' + + '

Utføre et menyelement eller en knapp på en verktøylinje

\n' + + '\n' + + '

Når det ønskede menyelementet eller verktøylinjeknappen er uthevet, trykker du på Retur, Enter,\n' + + ' eller mellomromstasten for å utføre elementet.

\n' + + '\n' + + '

Navigere i dialogbokser uten faner

\n' + + '\n' + + '

I dialogbokser uten faner blir den første interaktive komponenten uthevet når dialogboksen åpnes.

\n' + + '\n' + + '

Naviger mellom interaktive komponenter i dialogboksen ved å trykke på tabulatortasten eller Shift + tabulatortasten.

\n' + + '\n' + + '

Navigere i fanebaserte dialogbokser

\n' + + '\n' + + '

I fanebaserte dialogbokser blir den første knappen i fanemenyen uthevet når dialogboksen åpnes.

\n' + + '\n' + + '

Naviger mellom interaktive komponenter i fanen ved å trykke på tabulatortasten eller\n' + + ' Shift + tabulatortasten.

\n' + + '\n' + + '

Veksle til en annen fane i dialogboksen ved å utheve fanemenyen, og trykk deretter på den aktuelle piltasten\n' + + ' for å bevege deg mellom de tilgjengelige fanene.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nl.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nl.js new file mode 100644 index 0000000..05c07ae --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nl.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.nl', +'

Toetsenbordnavigatie starten

\n' + + '\n' + + '
\n' + + '
Focus op de menubalk instellen
\n' + + '
Windows of Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Focus op de werkbalk instellen
\n' + + '
Windows of Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Focus op de voettekst instellen
\n' + + '
Windows of Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Focus op de melding instellen
\n' + + '
Windows of Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Focus op een contextuele werkbalk instellen
\n' + + '
Windows, Linux of macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

De navigatie start bij het eerste UI-item, dat wordt gemarkeerd of onderstreept als het eerste item zich in\n' + + ' in het elementenpad van de voettekst bevindt.

\n' + + '\n' + + '

Navigeren tussen UI-secties

\n' + + '\n' + + '

Druk op Tab om naar de volgende UI-sectie te gaan.

\n' + + '\n' + + '

Druk op Shift+Tab om naar de vorige UI-sectie te gaan.

\n' + + '\n' + + '

De Tab-volgorde van deze UI-secties is:

\n' + + '\n' + + '
    \n' + + '
  1. Menubalk
  2. \n' + + '
  3. Elke werkbalkgroep
  4. \n' + + '
  5. Zijbalk
  6. \n' + + '
  7. Elementenpad in de voettekst
  8. \n' + + '
  9. Wisselknop voor aantal woorden in de voettekst
  10. \n' + + '
  11. Merkkoppeling in de voettekst
  12. \n' + + '
  13. Greep voor het wijzigen van het formaat van de editor in de voettekst
  14. \n' + + '
\n' + + '\n' + + '

Als een UI-sectie niet aanwezig is, wordt deze overgeslagen.

\n' + + '\n' + + '

Als de focus van de toetsenbordnavigatie is ingesteld op de voettekst en er geen zichtbare zijbalk is, kun je op Shift+Tab drukken\n' + + ' om de focus naar de eerste werkbalkgroep in plaats van de laatste te verplaatsen.

\n' + + '\n' + + '

Navigeren binnen UI-secties

\n' + + '\n' + + '

Druk op de pijltjestoets om naar het betreffende UI-element te gaan.

\n' + + '\n' + + '

Met de pijltjestoetsen Links en Rechts

\n' + + '\n' + + '
    \n' + + "
  • wissel je tussen menu's in de menubalk.
  • \n" + + '
  • open je een submenu in een menu.
  • \n' + + '
  • wissel je tussen knoppen in een werkbalkgroep.
  • \n' + + '
  • wissel je tussen items in het elementenpad in de voettekst.
  • \n' + + '
\n' + + '\n' + + '

Met de pijltjestoetsen Omlaag en Omhoog

\n' + + '\n' + + '
    \n' + + '
  • wissel je tussen menu-items in een menu.
  • \n' + + '
  • wissel je tussen items in een werkbalkpop-upmenu.
  • \n' + + '
\n' + + '\n' + + '

Met de pijltjestoetsen wissel je binnen de UI-sectie waarop de focus is ingesteld.

\n' + + '\n' + + '

Druk op de toets Esc om een geopend menu, submenu of pop-upmenu te sluiten.

\n' + + '\n' + + "

Als de huidige focus is ingesteld 'bovenaan' een bepaalde UI-sectie, kun je op de toets Esc drukken\n" + + ' om de toetsenbordnavigatie af te sluiten.

\n' + + '\n' + + '

Een menu-item of werkbalkknop uitvoeren

\n' + + '\n' + + '

Als het gewenste menu-item of de gewenste werkbalkknop is gemarkeerd, kun je op Return, Enter\n' + + ' of de spatiebalk drukken om het item uit te voeren.

\n' + + '\n' + + '

Navigeren in dialoogvensters zonder tabblad

\n' + + '\n' + + '

Als een dialoogvenster zonder tabblad wordt geopend, wordt de focus ingesteld op het eerste interactieve onderdeel.

\n' + + '\n' + + '

Je kunt navigeren tussen interactieve onderdelen van een dialoogvenster door op Tab of Shift+Tab te drukken.

\n' + + '\n' + + '

Navigeren in dialoogvensters met tabblad

\n' + + '\n' + + '

Als een dialoogvenster met tabblad wordt geopend, wordt de focus ingesteld op de eerste knop in het tabbladmenu.

\n' + + '\n' + + '

Je kunt navigeren tussen interactieve onderdelen van dit tabblad van het dialoogvenster door op Tab of\n' + + ' Shift+Tab te drukken.

\n' + + '\n' + + '

Je kunt overschakelen naar een ander tabblad van het dialoogvenster door de focus in te stellen op het tabbladmenu en vervolgens op de juiste pijltjestoets\n' + + ' te drukken om tussen de beschikbare tabbladen te wisselen.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pl.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pl.js new file mode 100644 index 0000000..e89f808 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pl.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.pl', +'

Początek nawigacji przy użyciu klawiatury

\n' + + '\n' + + '
\n' + + '
Ustaw fokus na pasek menu
\n' + + '
Windows lub Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Ustaw fokus na pasek narzędzi
\n' + + '
Windows lub Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Ustaw fokus na sekcję Footer
\n' + + '
Windows lub Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Skup się na powiadomieniu
\n' + + '
Windows lub Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Ustaw fokus na kontekstowy pasek narzędzi
\n' + + '
Windows, Linux lub macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Nawigacja zostanie rozpoczęta od pierwszego elementu interfejsu użytkownika, który jest podświetlony lub — w przypadku pierwszego elementu\n' + + ' w ścieżce elementów w sekcji Footer — podkreślony.

\n' + + '\n' + + '

Nawigacja pomiędzy sekcjami interfejsu użytkownika

\n' + + '\n' + + '

Aby przenieść się z danej sekcji interfejsu użytkownika do następnej, naciśnij Tab.

\n' + + '\n' + + '

Aby przenieść się z danej sekcji interfejsu użytkownika do poprzedniej, naciśnij Shift+Tab.

\n' + + '\n' + + '

Kolejność klawisza Tab w takich sekcjach interfejsu użytkownika jest następująca:

\n' + + '\n' + + '
    \n' + + '
  1. Pasek menu
  2. \n' + + '
  3. Każda grupa na pasku narzędzi
  4. \n' + + '
  5. Pasek boczny
  6. \n' + + '
  7. Ścieżka elementów w sekcji Footer
  8. \n' + + '
  9. Przycisk przełączania liczby słów w sekcji Footer
  10. \n' + + '
  11. Łącze brandujące w sekcji Footer
  12. \n' + + '
  13. Uchwyt zmiany rozmiaru edytora w sekcji Footer
  14. \n' + + '
\n' + + '\n' + + '

Jeżeli nie ma sekcji interfejsu użytkownika, jest to pomijane.

\n' + + '\n' + + '

Jeżeli na sekcji Footer jest ustawiony fokus nawigacji przy użyciu klawiatury i nie ma widocznego paska bocznego, naciśnięcie Shift+Tab\n' + + ' przenosi fokus na pierwszą grupę paska narzędzi, a nie na ostatnią.

\n' + + '\n' + + '

Nawigacja wewnątrz sekcji interfejsu użytkownika

\n' + + '\n' + + '

Aby przenieść się z danego elementu interfejsu użytkownika do następnego, naciśnij odpowiedni klawisz strzałki.

\n' + + '\n' + + '

Klawisze strzałek w prawo i w lewo służą do

\n' + + '\n' + + '
    \n' + + '
  • przenoszenia się pomiędzy menu na pasku menu,
  • \n' + + '
  • otwarcia podmenu w menu,
  • \n' + + '
  • przenoszenia się pomiędzy przyciskami w grupie paska narzędzi,
  • \n' + + '
  • przenoszenia się pomiędzy elementami w ścieżce elementów w sekcji Footer.
  • \n' + + '
\n' + + '\n' + + '

Klawisze strzałek w dół i w górę służą do

\n' + + '\n' + + '
    \n' + + '
  • przenoszenia się pomiędzy elementami menu w menu,
  • \n' + + '
  • przenoszenia się pomiędzy elementami w wyskakującym menu paska narzędzi.
  • \n' + + '
\n' + + '\n' + + '

Klawisze strzałek służą do przemieszczania się w sekcji interfejsu użytkownika z ustawionym fokusem.

\n' + + '\n' + + '

Aby zamknąć otwarte menu, otwarte podmenu lub otwarte menu wyskakujące, naciśnij klawisz Esc.

\n' + + '\n' + + '

Jeżeli fokus jest ustawiony na górze konkretnej sekcji interfejsu użytkownika, naciśnięcie klawisza Esc powoduje wyjście\n' + + ' z nawigacji przy użyciu klawiatury.

\n' + + '\n' + + '

Wykonanie elementu menu lub przycisku paska narzędzi

\n' + + '\n' + + '

Gdy podświetlony jest żądany element menu lub przycisk paska narzędzi, naciśnij klawisz Return, Enter\n' + + ' lub Spacja, aby go wykonać.

\n' + + '\n' + + '

Nawigacja po oknie dialogowym bez kart

\n' + + '\n' + + '

Gdy otwiera się okno dialogowe bez kart, fokus ustawiany jest na pierwszą interaktywną część okna.

\n' + + '\n' + + '

Pomiędzy interaktywnymi częściami okna dialogowego nawiguj, naciskając klawisze Tab lub Shift+Tab.

\n' + + '\n' + + '

Nawigacja po oknie dialogowym z kartami

\n' + + '\n' + + '

W przypadku okna dialogowego z kartami po otwarciu okna dialogowego fokus ustawiany jest na pierwszy przycisk w menu karty.

\n' + + '\n' + + '

Nawigację pomiędzy interaktywnymi częściami karty okna dialogowego prowadzi się poprzez naciskanie klawiszy Tab lub\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Przełączenie się na inną kartę okna dialogowego wykonuje się poprzez ustawienie fokusu na menu karty i naciśnięcie odpowiedniego klawisza strzałki\n' + + ' w celu przemieszczenia się pomiędzy dostępnymi kartami.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_BR.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_BR.js new file mode 100644 index 0000000..2938fcf --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_BR.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.pt_BR', +'

Iniciar navegação pelo teclado

\n' + + '\n' + + '
\n' + + '
Foco na barra de menus
\n' + + '
Windows ou Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Foco na barra de ferramentas
\n' + + '
Windows ou Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Foco no rodapé
\n' + + '
Windows ou Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Foco na notificação
\n' + + '
Windows ou Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Foco na barra de ferramentas contextual
\n' + + '
Windows, Linux ou macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

A navegação inicia no primeiro item da IU, que será destacado ou sublinhado no caso do primeiro item no\n' + + ' caminho do elemento Rodapé.

\n' + + '\n' + + '

Navegar entre seções da IU

\n' + + '\n' + + '

Para ir de uma seção da IU para a seguinte, pressione Tab.

\n' + + '\n' + + '

Para ir de uma seção da IU para a anterior, pressione Shift+Tab.

\n' + + '\n' + + '

A ordem de Tab destas seções da IU é:

\n' + + '\n' + + '
    \n' + + '
  1. Barra de menus
  2. \n' + + '
  3. Cada grupo da barra de ferramentas
  4. \n' + + '
  5. Barra lateral
  6. \n' + + '
  7. Caminho do elemento no rodapé
  8. \n' + + '
  9. Botão de alternar contagem de palavras no rodapé
  10. \n' + + '
  11. Link da marca no rodapé
  12. \n' + + '
  13. Alça de redimensionamento do editor no rodapé
  14. \n' + + '
\n' + + '\n' + + '

Se não houver uma seção da IU, ela será pulada.

\n' + + '\n' + + '

Se o rodapé tiver o foco da navegação pelo teclado e não houver uma barra lateral visível, pressionar Shift+Tab\n' + + ' move o foco para o primeiro grupo da barra de ferramentas, não para o último.

\n' + + '\n' + + '

Navegar dentro das seções da IU

\n' + + '\n' + + '

Para ir de um elemento da IU para o seguinte, pressione a Seta correspondente.

\n' + + '\n' + + '

As teclas de seta Esquerda e Direita

\n' + + '\n' + + '
    \n' + + '
  • movem entre menus na barra de menus.
  • \n' + + '
  • abrem um submenu em um menu.
  • \n' + + '
  • movem entre botões em um grupo da barra de ferramentas.
  • \n' + + '
  • movem entre itens no caminho do elemento do rodapé.
  • \n' + + '
\n' + + '\n' + + '

As teclas de seta Abaixo e Acima

\n' + + '\n' + + '
    \n' + + '
  • movem entre itens de menu em um menu.
  • \n' + + '
  • movem entre itens em um menu suspenso da barra de ferramentas.
  • \n' + + '
\n' + + '\n' + + '

As teclas de Seta alternam dentre a seção da IU em foco.

\n' + + '\n' + + '

Para fechar um menu aberto, um submenu aberto ou um menu suspenso aberto, pressione Esc.

\n' + + '\n' + + '

Se o foco atual estiver no ‘alto’ de determinada seção da IU, pressionar Esc também sai\n' + + ' totalmente da navegação pelo teclado.

\n' + + '\n' + + '

Executar um item de menu ou botão da barra de ferramentas

\n' + + '\n' + + '

Com o item de menu ou botão da barra de ferramentas desejado destacado, pressione Return, Enter,\n' + + ' ou a Barra de espaço para executar o item.

\n' + + '\n' + + '

Navegar por caixas de diálogo sem guias

\n' + + '\n' + + '

Em caixas de diálogo sem guias, o primeiro componente interativo recebe o foco quando a caixa de diálogo abre.

\n' + + '\n' + + '

Navegue entre componentes interativos de caixa de diálogo pressionando Tab ou Shift+Tab.

\n' + + '\n' + + '

Navegar por caixas de diálogo com guias

\n' + + '\n' + + '

Em caixas de diálogo com guias, o primeiro botão no menu da guia recebe o foco quando a caixa de diálogo abre.

\n' + + '\n' + + '

Navegue entre componentes interativos dessa guia da caixa de diálogo pressionando Tab ou\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Alterne para outra guia da caixa de diálogo colocando o foco no menu da guia e pressionando a Seta\n' + + ' adequada para percorrer as guias disponíveis.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_PT.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_PT.js new file mode 100644 index 0000000..03da3d6 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_PT.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.pt_PT', +'

Iniciar navegação com teclado

\n' + + '\n' + + '
\n' + + '
Foco na barra de menu
\n' + + '
Windows ou Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Foco na barra de ferramentas
\n' + + '
Windows ou Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Foco no rodapé
\n' + + '
Windows ou Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Focar a notificação
\n' + + '
Windows ou Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Foco numa barra de ferramentas contextual
\n' + + '
Windows, Linux ou macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

A navegação começará no primeiro item de IU, que estará realçado ou sublinhado, no caso do primeiro item no\n' + + ' caminho do elemento do rodapé.

\n' + + '\n' + + '

Navegar entre secções de IU

\n' + + '\n' + + '

Para se mover de uma secção de IU para a seguinte, prima Tab.

\n' + + '\n' + + '

Para se mover de uma secção de IU para a anterior, prima Shift+Tab.

\n' + + '\n' + + '

A ordem de tabulação destas secções de IU é:

\n' + + '\n' + + '
    \n' + + '
  1. Barra de menu
  2. \n' + + '
  3. Cada grupo da barra de ferramentas
  4. \n' + + '
  5. Barra lateral
  6. \n' + + '
  7. Caminho do elemento no rodapé
  8. \n' + + '
  9. Botão de alternar da contagem de palavras no rodapé
  10. \n' + + '
  11. Ligação da marca no rodapé
  12. \n' + + '
  13. Alça de redimensionamento do editor no rodapé
  14. \n' + + '
\n' + + '\n' + + '

Se uma secção de IU não estiver presente, é ignorada.

\n' + + '\n' + + '

Se o rodapé tiver foco de navegação com teclado e não existir uma barra lateral visível, premir Shift+Tab\n' + + ' move o foco para o primeiro grupo da barra de ferramentas e não para o último.

\n' + + '\n' + + '

Navegar nas secções de IU

\n' + + '\n' + + '

Para se mover de um elemento de IU para o seguinte, prima a tecla de seta adequada.

\n' + + '\n' + + '

As teclas de seta Para a esquerda e Para a direita

\n' + + '\n' + + '
    \n' + + '
  • movem-se entre menus na barra de menu.
  • \n' + + '
  • abrem um submenu num menu.
  • \n' + + '
  • movem-se entre botões num grupo da barra de ferramentas.
  • \n' + + '
  • movem-se entre itens no caminho do elemento do rodapé.
  • \n' + + '
\n' + + '\n' + + '

As teclas de seta Para cima e Para baixo

\n' + + '\n' + + '
    \n' + + '
  • movem-se entre itens de menu num menu.
  • \n' + + '
  • movem-se entre itens num menu de pop-up da barra de ferramentas.
  • \n' + + '
\n' + + '\n' + + '

As teclas de seta deslocam-se ciclicamente na secção de IU em foco.

\n' + + '\n' + + '

Para fechar um menu aberto, um submenu aberto ou um menu de pop-up aberto, prima a tecla Esc.

\n' + + '\n' + + '

Se o foco atual estiver no "topo" de determinada secção de IU, premir a tecla Esc também fecha\n' + + ' completamente a navegação com teclado.

\n' + + '\n' + + '

Executar um item de menu ou botão da barra de ferramentas

\n' + + '\n' + + '

Quando o item de menu ou o botão da barra de ferramentas pretendido estiver realçado, prima Retrocesso, Enter\n' + + ' ou a Barra de espaço para executar o item.

\n' + + '\n' + + '

Navegar em diálogos sem separadores

\n' + + '\n' + + '

Nos diálogos sem separadores, o primeiro componente interativo fica em foco quando o diálogo abre.

\n' + + '\n' + + '

Navegue entre componentes interativos do diálogo, premindo Tab ou Shift+Tab.

\n' + + '\n' + + '

Navegar em diálogos com separadores

\n' + + '\n' + + '

Nos diálogos com separadores, o primeiro botão no menu do separador fica em foco quando o diálogo abre.

\n' + + '\n' + + '

Navegue entre os componentes interativos deste separador do diálogo, premindo Tab ou\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Mude para outro separador do diálogo colocando o menu do separador em foco e, em seguida, premindo a tecla de seta\n' + + ' adequada para se deslocar ciclicamente pelos separadores disponíveis.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ro.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ro.js new file mode 100644 index 0000000..38d3441 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ro.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ro', +'

Începeți navigarea de la tastatură

\n' + + '\n' + + '
\n' + + '
Focalizare pe bara de meniu
\n' + + '
Windows sau Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Focalizare pe bara de instrumente
\n' + + '
Windows sau Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Focalizare pe subsol
\n' + + '
Windows sau Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Focalizare pe notificare
\n' + + '
Windows sau Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Focalizare pe o bară de instrumente contextuală
\n' + + '
Windows, Linux sau macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigarea va începe de la primul element al interfeței cu utilizatorul, care va fi evidențiat sau subliniat în cazul primului element din\n' + + ' calea elementului Subsol.

\n' + + '\n' + + '

Navigați între secțiunile interfeței cu utilizatorul

\n' + + '\n' + + '

Pentru a trece de la o secțiune a interfeței cu utilizatorul la alta, apăsați Tab.

\n' + + '\n' + + '

Pentru a trece de la o secțiune a interfeței cu utilizatorul la cea anterioară, apăsați Shift+Tab.

\n' + + '\n' + + '

Ordinea cu Tab a acestor secțiuni ale interfeței cu utilizatorul este următoarea:

\n' + + '\n' + + '
    \n' + + '
  1. Bara de meniu
  2. \n' + + '
  3. Fiecare grup de bare de instrumente
  4. \n' + + '
  5. Bara laterală
  6. \n' + + '
  7. Calea elementului în subsol
  8. \n' + + '
  9. Buton de comutare a numărului de cuvinte în subsol
  10. \n' + + '
  11. Link de branding în subsol
  12. \n' + + '
  13. Mâner de redimensionare a editorului în subsol
  14. \n' + + '
\n' + + '\n' + + '

În cazul în care o secțiune a interfeței cu utilizatorul nu este prezentă, aceasta este omisă.

\n' + + '\n' + + '

În cazul în care subsolul are focalizarea navigației asupra tastaturii și nu există o bară laterală vizibilă, apăsarea butonului Shift+Tab\n' + + ' mută focalizarea pe primul grup de bare de instrumente, nu pe ultimul.

\n' + + '\n' + + '

Navigați în secțiunile interfeței cu utilizatorul

\n' + + '\n' + + '

Pentru a trece de la un element de interfață cu utilizatorul la următorul, apăsați tasta cu săgeata corespunzătoare.

\n' + + '\n' + + '

Tastele cu săgeți către stânga și dreapta

\n' + + '\n' + + '
    \n' + + '
  • navighează între meniurile din bara de meniuri.
  • \n' + + '
  • deschid un sub-meniu dintr-un meniu.
  • \n' + + '
  • navighează între butoanele dintr-un grup de bare de instrumente.
  • \n' + + '
  • navighează între elementele din calea elementelor subsolului.
  • \n' + + '
\n' + + '\n' + + '

Tastele cu săgeți în sus și în jos

\n' + + '\n' + + '
    \n' + + '
  • navighează între elementele de meniu dintr-un meniu.
  • \n' + + '
  • navighează între elementele unui meniu pop-up din bara de instrumente.
  • \n' + + '
\n' + + '\n' + + '

Tastele cu săgeți navighează în cadrul secțiunii interfeței cu utilizatorul asupra căreia se focalizează.

\n' + + '\n' + + '

Pentru a închide un meniu deschis, un sub-meniu deschis sau un meniu pop-up deschis, apăsați tasta Esc.

\n' + + '\n' + + '

Dacă focalizarea curentă este asupra „părții superioare” a unei anumite secțiuni a interfeței cu utilizatorul, prin apăsarea tastei Esc se iese, de asemenea,\n' + + ' în întregime din navigarea de la tastatură.

\n' + + '\n' + + '

Executarea unui element de meniu sau a unui buton din bara de instrumente

\n' + + '\n' + + '

Atunci când elementul de meniu dorit sau butonul dorit din bara de instrumente este evidențiat, apăsați Return, Enter,\n' + + ' sau bara de spațiu pentru a executa elementul.

\n' + + '\n' + + '

Navigarea de dialoguri fără file

\n' + + '\n' + + '

În dialogurile fără file, prima componentă interactivă beneficiază de focalizare la deschiderea dialogului.

\n' + + '\n' + + '

Navigați între componentele dialogului interactiv apăsând Tab sau Shift+Tab.

\n' + + '\n' + + '

Navigarea de dialoguri cu file

\n' + + '\n' + + '

În dialogurile cu file, primul buton din meniul cu file beneficiază de focalizare la deschiderea dialogului.

\n' + + '\n' + + '

Navigați între componentele interactive ale acestei file de dialog apăsând Tab sau\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Treceți la o altă filă de dialog focalizând asupra meniului cu file și apoi apăsând săgeata corespunzătoare\n' + + ' pentru a parcurge filele disponibile.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ru.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ru.js new file mode 100644 index 0000000..d310f54 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ru.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.ru', +'

Начните управление с помощью клавиатуры

\n' + + '\n' + + '
\n' + + '
Фокус на панели меню
\n' + + '
Windows или Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Фокус на панели инструментов
\n' + + '
Windows или Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Фокус на нижнем колонтитуле
\n' + + '
Windows или Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Фокус на уведомлении
\n' + + '
Windows или Linux: Alt+12
\n' + + '
macOS: ⌥F12
\n' + + '
Фокус на контекстной панели инструментов
\n' + + '
Windows, Linux или macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Первый доступный для управления элемент интерфейса будет выделен цветом или подчеркнут (если он находится\n' + + ' в пути элементов нижнего колонтитула).

\n' + + '\n' + + '

Переход между разделами пользовательского интерфейса

\n' + + '\n' + + '

Чтобы перейти из текущего раздела интерфейса в следующий, нажмите Tab.

\n' + + '\n' + + '

Чтобы перейти из текущего раздела интерфейса в предыдущий, нажмите Shift+Tab.

\n' + + '\n' + + '

Вкладки разделов интерфейса расположены в следующем порядке:

\n' + + '\n' + + '
    \n' + + '
  1. Панель меню
  2. \n' + + '
  3. Группы панели инструментов
  4. \n' + + '
  5. Боковая панель
  6. \n' + + '
  7. Путь элементов нижнего колонтитула
  8. \n' + + '
  9. Подсчет слов/символов в нижнем колонтитуле
  10. \n' + + '
  11. Брендовая ссылка в нижнем колонтитуле
  12. \n' + + '
  13. Угол для изменения размера окна редактора
  14. \n' + + '
\n' + + '\n' + + '

Если раздел интерфейса отсутствует, он пропускается.

\n' + + '\n' + + '

Если при управлении с клавиатуры фокус находится на нижнем колонтитуле, а видимая боковая панель отсутствует, то при нажатии сочетания клавиш Shift+Tab\n' + + ' фокус переносится на первую группу панели инструментов, а не на последнюю.

\n' + + '\n' + + '

Переход между элементами внутри разделов пользовательского интерфейса

\n' + + '\n' + + '

Чтобы перейти от текущего элемента интерфейса к следующему, нажмите соответствующую клавишу со стрелкой.

\n' + + '\n' + + '

Клавиши со стрелками влево и вправо позволяют

\n' + + '\n' + + '
    \n' + + '
  • перемещаться между разными меню в панели меню.
  • \n' + + '
  • открывать разделы меню.
  • \n' + + '
  • перемещаться между кнопками в группе панели инструментов.
  • \n' + + '
  • перемещаться между элементами в пути элементов нижнего колонтитула.
  • \n' + + '
\n' + + '\n' + + '

Клавиши со стрелками вниз и вверх позволяют

\n' + + '\n' + + '
    \n' + + '
  • перемещаться между элементами одного меню.
  • \n' + + '
  • перемещаться между элементами всплывающего меню в панели инструментов.
  • \n' + + '
\n' + + '\n' + + '

При использовании клавиш со стрелками вы будете циклически перемещаться по элементам в пределах выбранного раздела интерфейса.

\n' + + '\n' + + '

Чтобы закрыть открытое меню, его раздел или всплывающее меню, нажмите клавишу Esc.

\n' + + '\n' + + '

Если фокус находится наверху какого-либо раздела интерфейса, нажатие клавиши Esc также приведет\n' + + ' к выходу из режима управления с помощью клавиатуры.

\n' + + '\n' + + '

Использование элемента меню или кнопки на панели инструментов

\n' + + '\n' + + '

Когда элемент меню или кнопка панели инструментов будут выделены, нажмите Return, Enter\n' + + ' или Space, чтобы их активировать.

\n' + + '\n' + + '

Управление в диалоговом окне без вкладок

\n' + + '\n' + + '

При открытии диалогового окна без вкладок фокус переносится на первый интерактивный компонент.

\n' + + '\n' + + '

Для перехода между интерактивными компонентами диалогового окна нажимайте Tab или Shift+Tab.

\n' + + '\n' + + '

Управление в диалоговом окне с вкладками

\n' + + '\n' + + '

При открытии диалогового окна с вкладками фокус переносится на первую кнопку в меню вкладок.

\n' + + '\n' + + '

Для перехода между интерактивными компонентами этой вкладки диалогового окна нажимайте Tab или\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Для перехода на другую вкладку диалогового окна переместите фокус на меню вкладок, а затем используйте клавиши со стрелками\n' + + ' для циклического переключения между доступными вкладками.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sk.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sk.js new file mode 100644 index 0000000..60cc628 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sk.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.sk', +'

Začíname s navigáciou pomocou klávesnice

\n' + + '\n' + + '
\n' + + '
Prejsť na panel s ponukami
\n' + + '
Windows alebo Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Prejsť na panel nástrojov
\n' + + '
Windows alebo Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Prejsť na pätičku
\n' + + '
Windows alebo Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Zaostriť na oznámenie
\n' + + '
Windows alebo Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Prejsť na kontextový panel nástrojov
\n' + + '
Windows, Linux alebo macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigácia začne pri prvej položke používateľského rozhrania, ktorá bude zvýraznená alebo v prípade prvej položky\n' + + ' cesty k pätičke podčiarknutá.

\n' + + '\n' + + '

Navigácia medzi časťami používateľského rozhrania

\n' + + '\n' + + '

Ak sa chcete posunúť z jednej časti používateľského rozhrania do druhej, stlačte tlačidlo Tab.

\n' + + '\n' + + '

Ak sa chcete posunúť z jednej časti používateľského rozhrania do predchádzajúcej, stlačte tlačidlá Shift + Tab.

\n' + + '\n' + + '

Poradie prepínania medzi týmito časťami používateľského rozhrania pri stláčaní tlačidla Tab:

\n' + + '\n' + + '
    \n' + + '
  1. Panel s ponukou
  2. \n' + + '
  3. Každá skupina panela nástrojov
  4. \n' + + '
  5. Bočný panel
  6. \n' + + '
  7. Cesta k prvku v pätičke
  8. \n' + + '
  9. Prepínač počtu slov v pätičke
  10. \n' + + '
  11. Odkaz na informácie o značke v pätičke
  12. \n' + + '
  13. Úchyt na zmenu veľkosti editora v pätičke
  14. \n' + + '
\n' + + '\n' + + '

Ak nejaká časť používateľského rozhrania nie je prítomná, preskočí sa.

\n' + + '\n' + + '

Ak je pätička vybratá na navigáciu pomocou klávesnice a nie je viditeľný bočný panel, stlačením klávesov Shift+Tab\n' + + ' prejdete na prvú skupinu panela nástrojov, nie na poslednú.

\n' + + '\n' + + '

Navigácia v rámci častí používateľského rozhrania

\n' + + '\n' + + '

Ak sa chcete posunúť z jedného prvku používateľského rozhrania na ďalší, stlačte príslušný kláves so šípkou.

\n' + + '\n' + + '

Klávesy so šípkami doľava a doprava

\n' + + '\n' + + '
    \n' + + '
  • umožňujú presun medzi ponukami na paneli ponúk,
  • \n' + + '
  • otvárajú podponuku v rámci ponuky,
  • \n' + + '
  • umožňujú presun medzi tlačidlami v skupine panelov nástrojov,
  • \n' + + '
  • umožňujú presun medzi položkami cesty prvku v pätičke.
  • \n' + + '
\n' + + '\n' + + '

Klávesy so šípkami dole a hore

\n' + + '\n' + + '
    \n' + + '
  • umožňujú presun medzi položkami ponuky,
  • \n' + + '
  • umožňujú presun medzi položkami v kontextovej ponuke panela nástrojov.
  • \n' + + '
\n' + + '\n' + + '

Klávesy so šípkami vykonávajú prepínanie v rámci vybranej časti používateľského rozhrania.

\n' + + '\n' + + '

Ak chcete zatvoriť otvorenú ponuku, otvorenú podponuku alebo otvorenú kontextovú ponuku, stlačte kláves Esc.

\n' + + '\n' + + '

Ak je aktuálne vybratá horná časť konkrétneho používateľského rozhrania, stlačením klávesu Esc úplne ukončíte tiež\n' + + ' navigáciu pomocou klávesnice.

\n' + + '\n' + + '

Vykonanie príkazu položky ponuky alebo tlačidla panela nástrojov

\n' + + '\n' + + '

Keď je zvýraznená požadovaná položka ponuky alebo tlačidlo panela nástrojov, stlačením klávesov Return, Enter\n' + + ' alebo medzerníka vykonáte príslušný príkaz položky.

\n' + + '\n' + + '

Navigácia v dialógových oknách bez záložiek

\n' + + '\n' + + '

Pri otvorení dialógových okien bez záložiek prejdete na prvý interaktívny komponent.

\n' + + '\n' + + '

Medzi interaktívnymi dialógovými komponentmi môžete prechádzať stlačením klávesov Tab alebo Shift+Tab.

\n' + + '\n' + + '

Navigácia v dialógových oknách so záložkami

\n' + + '\n' + + '

Pri otvorení dialógových okien so záložkami prejdete na prvé tlačidlo v ponuke záložiek.

\n' + + '\n' + + '

Medzi interaktívnymi komponentmi tejto dialógovej záložky môžete prechádzať stlačením klávesov Tab alebo\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Ak chcete prepnúť na ďalšiu záložku dialógového okna, prejdite do ponuky záložiek a potom môžete stlačením príslušného klávesu so šípkou\n' + + ' prepínať medzi dostupnými záložkami.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sl_SI.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sl_SI.js new file mode 100644 index 0000000..2b25f5a --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sl_SI.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.sl_SI', +'

Začetek krmarjenja s tipkovnico

\n' + + '\n' + + '
\n' + + '
Fokus na menijsko vrstico
\n' + + '
Windows ali Linux: Alt + F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokus na orodno vrstico
\n' + + '
Windows ali Linux: Alt + F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokus na nogo
\n' + + '
Windows ali Linux: Alt + F11
\n' + + '
macOS: ⌥F11
\n' + + '
Označitev obvestila
\n' + + '
Windows ali Linux: Alt + F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokus na kontekstualno orodno vrstico
\n' + + '
Windows, Linux ali macOS: Ctrl + F9
\n' + + '
\n' + + '\n' + + '

Krmarjenje se bo začelo s prvim elementom uporabniškega vmesnika, ki bo izpostavljena ali podčrtan, če gre za prvi element na\n' + + ' poti do elementa noge.

\n' + + '\n' + + '

Krmarjenje med razdelki uporabniškega vmesnika

\n' + + '\n' + + '

Če se želite pomakniti z enega dela uporabniškega vmesnika na naslednjega, pritisnite tabulatorko.

\n' + + '\n' + + '

Če se želite pomakniti z enega dela uporabniškega vmesnika na prejšnjega, pritisnite shift + tabulatorko.

\n' + + '\n' + + '

Zaporedje teh razdelkov uporabniškega vmesnika, ko pritiskate tabulatorko, je:

\n' + + '\n' + + '
    \n' + + '
  1. Menijska vrstica
  2. \n' + + '
  3. Posamezne skupine orodne vrstice
  4. \n' + + '
  5. Stranska vrstica
  6. \n' + + '
  7. Pod do elementa v nogi
  8. \n' + + '
  9. Gumb za preklop štetja besed v nogi
  10. \n' + + '
  11. Povezava do blagovne znamke v nogi
  12. \n' + + '
  13. Ročaj za spreminjanje velikosti urejevalnika v nogi
  14. \n' + + '
\n' + + '\n' + + '

Če razdelek uporabniškega vmesnika ni prisoten, je preskočen.

\n' + + '\n' + + '

Če ima noga fokus za krmarjenje s tipkovnico in ni vidne stranske vrstice, s pritiskom na shift + tabulatorko\n' + + ' fokus premaknete na prvo skupino orodne vrstice, ne zadnjo.

\n' + + '\n' + + '

Krmarjenje v razdelkih uporabniškega vmesnika

\n' + + '\n' + + '

Če se želite premakniti z enega elementa uporabniškega vmesnika na naslednjega, pritisnite ustrezno puščično tipko.

\n' + + '\n' + + '

Leva in desna puščična tipka

\n' + + '\n' + + '
    \n' + + '
  • omogočata premikanje med meniji v menijski vrstici.
  • \n' + + '
  • odpreta podmeni v meniju.
  • \n' + + '
  • omogočata premikanje med gumbi v skupini orodne vrstice.
  • \n' + + '
  • omogočata premikanje med elementi na poti do elementov noge.
  • \n' + + '
\n' + + '\n' + + '

Spodnja in zgornja puščična tipka

\n' + + '\n' + + '
    \n' + + '
  • omogočata premikanje med elementi menija.
  • \n' + + '
  • omogočata premikanje med elementi v pojavnem meniju orodne vrstice.
  • \n' + + '
\n' + + '\n' + + '

Puščične tipke omogočajo kroženje znotraj razdelka uporabniškega vmesnika, na katerem je fokus.

\n' + + '\n' + + '

Če želite zapreti odprt meni, podmeni ali pojavni meni, pritisnite tipko Esc.

\n' + + '\n' + + '

Če je trenutni fokus na »vrhu« določenega razdelka uporabniškega vmesnika, s pritiskom tipke Esc zaprete\n' + + ' tudi celotno krmarjenje s tipkovnico.

\n' + + '\n' + + '

Izvajanje menijskega elementa ali gumba orodne vrstice

\n' + + '\n' + + '

Ko je označen želeni menijski element ali orodja vrstica, pritisnite vračalko, Enter\n' + + ' ali preslednico, da izvedete element.

\n' + + '\n' + + '

Krmarjenje po pogovornih oknih brez zavihkov

\n' + + '\n' + + '

Ko odprete pogovorno okno brez zavihkov, ima fokus prva interaktivna komponenta.

\n' + + '\n' + + '

Med interaktivnimi komponentami pogovornega okna se premikate s pritiskom tabulatorke ali kombinacije tipke shift + tabulatorke.

\n' + + '\n' + + '

Krmarjenje po pogovornih oknih z zavihki

\n' + + '\n' + + '

Ko odprete pogovorno okno z zavihki, ima fokus prvi gumb v meniju zavihka.

\n' + + '\n' + + '

Med interaktivnimi komponentami tega zavihka pogovornega okna se premikate s pritiskom tabulatorke ali\n' + + ' kombinacije tipke shift + tabulatorke.

\n' + + '\n' + + '

Na drug zavihek pogovornega okna preklopite tako, da fokus prestavite na meni zavihka in nato pritisnete ustrezno puščično\n' + + ' tipko, da se pomaknete med razpoložljivimi zavihki.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sv_SE.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sv_SE.js new file mode 100644 index 0000000..c30f2f2 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sv_SE.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.sv_SE', +'

Påbörja tangentbordsnavigering

\n' + + '\n' + + '
\n' + + '
Fokusera på menyraden
\n' + + '
Windows eller Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Fokusera på verktygsraden
\n' + + '
Windows eller Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Fokusera på verktygsraden
\n' + + '
Windows eller Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Fokusera aviseringen
\n' + + '
Windows eller Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Fokusera på en snabbverktygsrad
\n' + + '
Windows, Linux eller macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Navigeringen börjar vid det första gränssnittsobjektet, vilket är markerat eller understruket om det gäller det första objektet i\n' + + ' sidfotens elementsökväg.

\n' + + '\n' + + '

Navigera mellan UI-avsnitt

\n' + + '\n' + + '

Flytta från ett UI-avsnitt till nästa genom att trycka på Tabb.

\n' + + '\n' + + '

Flytta från ett UI-avsnitt till det föregående genom att trycka på Skift+Tabb.

\n' + + '\n' + + '

Tabb-ordningen för dessa UI-avsnitt är:

\n' + + '\n' + + '
    \n' + + '
  1. Menyrad
  2. \n' + + '
  3. Varje verktygsradsgrupp
  4. \n' + + '
  5. Sidoruta
  6. \n' + + '
  7. Elementsökväg i sidfoten
  8. \n' + + '
  9. Växlingsknapp för ordantal i sidfoten
  10. \n' + + '
  11. Varumärkeslänk i sidfoten
  12. \n' + + '
  13. Storlekshandtag för redigeraren i sidfoten
  14. \n' + + '
\n' + + '\n' + + '

Om ett UI-avsnitt inte finns hoppas det över.

\n' + + '\n' + + '

Om sidfoten har fokus på tangentbordsnavigering, och det inte finns någon synlig sidoruta, flyttas fokus till den första verktygsradsgruppen\n' + + ' när du trycker på Skift+Tabb, inte till den sista.

\n' + + '\n' + + '

Navigera i UI-avsnitt

\n' + + '\n' + + '

Flytta från ett UI-element till nästa genom att trycka på motsvarande piltangent.

\n' + + '\n' + + '

Vänsterpil och högerpil

\n' + + '\n' + + '
    \n' + + '
  • flytta mellan menyer på menyraden.
  • \n' + + '
  • öppna en undermeny på en meny.
  • \n' + + '
  • flytta mellan knappar i en verktygsradgrupp.
  • \n' + + '
  • flytta mellan objekt i sidfotens elementsökväg.
  • \n' + + '
\n' + + '\n' + + '

Nedpil och uppil

\n' + + '\n' + + '
    \n' + + '
  • flytta mellan menyalternativ på en meny.
  • \n' + + '
  • flytta mellan alternativ på en popup-meny på verktygsraden.
  • \n' + + '
\n' + + '\n' + + '

Piltangenterna cirkulerar inom det fokuserade UI-avsnittet.

\n' + + '\n' + + '

Tryck på Esc-tangenten om du vill stänga en öppen meny, undermeny eller popup-meny.

\n' + + '\n' + + '

Om det aktuella fokuset är högst upp i ett UI-avsnitt avlutas även tangentbordsnavigeringen helt när\n' + + ' du trycker på Esc-tangenten.

\n' + + '\n' + + '

Köra ett menyalternativ eller en verktygfältsknapp

\n' + + '\n' + + '

När menyalternativet eller verktygsradsknappen är markerad trycker du på Retur, Enter\n' + + ' eller blanksteg för att köra alternativet.

\n' + + '\n' + + '

Navigera i dialogrutor utan flikar

\n' + + '\n' + + '

I dialogrutor utan flikar är den första interaktiva komponenten i fokus när dialogrutan öppnas.

\n' + + '\n' + + '

Navigera mellan interaktiva dialogkomponenter genom att trycka på Tabb eller Skift+Tabb.

\n' + + '\n' + + '

Navigera i dialogrutor med flikar

\n' + + '\n' + + '

I dialogrutor utan flikar är den första knappen på flikmenyn i fokus när dialogrutan öppnas.

\n' + + '\n' + + '

Navigera mellan interaktiva komponenter på dialogrutefliken genom att trycka på Tabb eller\n' + + ' Skift+Tabb.

\n' + + '\n' + + '

Växla till en annan dialogruta genom att fokusera på flikmenyn och sedan trycka på motsvarande piltangent\n' + + ' för att cirkulera mellan de tillgängliga flikarna.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/th_TH.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/th_TH.js new file mode 100644 index 0000000..562fe7a --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/th_TH.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.th_TH', +'

เริ่มต้นการนำทางด้วยแป้นพิมพ์

\n' + + '\n' + + '
\n' + + '
โฟกัสที่แถบเมนู
\n' + + '
Windows หรือ Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
โฟกัสที่แถบเครื่องมือ
\n' + + '
Windows หรือ Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
โฟกัสที่ส่วนท้าย
\n' + + '
Windows หรือ Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
โฟกัสไปที่การแจ้งเตือน
\n' + + '
Windows หรือ Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
โฟกัสที่แถบเครื่องมือตามบริบท
\n' + + '
Windows, Linux หรือ macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

การนำทางจะเริ่มที่รายการ UI แรก ซึ่งจะมีการไฮไลต์หรือขีดเส้นใต้ไว้ในกรณีที่รายการแรกอยู่ใน\n' + + ' พาธองค์ประกอบส่วนท้าย

\n' + + '\n' + + '

การนำทางระหว่างส่วนต่างๆ ของ UI

\n' + + '\n' + + '

ในการย้ายจากส่วน UI หนึ่งไปยังส่วนถัดไป ให้กด Tab

\n' + + '\n' + + '

ในการย้ายจากส่วน UI หนึ่งไปยังส่วนก่อนหน้า ให้กด Shift+Tab

\n' + + '\n' + + '

ลำดับแท็บของส่วนต่างๆ ของ UI คือ:

\n' + + '\n' + + '
    \n' + + '
  1. แถบเมนู
  2. \n' + + '
  3. แต่ละกลุ่มแถบเครื่องมือ
  4. \n' + + '
  5. แถบข้าง
  6. \n' + + '
  7. พาธองค์ประกอบในส่วนท้าย
  8. \n' + + '
  9. ปุ่มสลับเปิด/ปิดจำนวนคำในส่วนท้าย
  10. \n' + + '
  11. ลิงก์ชื่อแบรนด์ในส่วนท้าย
  12. \n' + + '
  13. จุดจับปรับขนาดของตัวแก้ไขในส่วนท้าย
  14. \n' + + '
\n' + + '\n' + + '

หากส่วน UI ไม่ปรากฏ แสดงว่าถูกข้ามไป

\n' + + '\n' + + '

หากส่วนท้ายมีการโฟกัสการนำทางแป้นพิมพ์และไม่มีแถบข้างปรากฏ การกด Shift+Tab\n' + + ' จะย้ายการโฟกัสไปที่กลุ่มแถบเครื่องมือแรก ไม่ใช่สุดท้าย

\n' + + '\n' + + '

การนำทางภายในส่วนต่างๆ ของ UI

\n' + + '\n' + + '

ในการย้ายจากองค์ประกอบ UI หนึ่งไปยังองค์ประกอบส่วนถัดไป ให้กดปุ่มลูกศรที่เหมาะสม

\n' + + '\n' + + '

ปุ่มลูกศรซ้ายและขวา

\n' + + '\n' + + '
    \n' + + '
  • ย้ายไปมาระหว่างเมนูต่างๆ ในแถบเมนู
  • \n' + + '
  • เปิดเมนูย่อยในเมนู
  • \n' + + '
  • ย้ายไปมาระหว่างปุ่มต่างๆ ในกลุ่มแถบเครื่องมือ
  • \n' + + '
  • ย้ายไปมาระหว่างรายการต่างๆ ในพาธองค์ประกอบของส่วนท้าย
  • \n' + + '
\n' + + '\n' + + '

ปุ่มลูกศรลงและขึ้น

\n' + + '\n' + + '
    \n' + + '
  • ย้ายไปมาระหว่างรายการเมนูต่างๆ ในเมนู
  • \n' + + '
  • ย้ายไปมาระหว่างรายการต่างๆ ในเมนูป๊อบอัพแถบเครื่องมือ
  • \n' + + '
\n' + + '\n' + + '

ปุ่มลูกศรจะเลื่อนไปมาภายในส่วน UI ที่โฟกัส

\n' + + '\n' + + '

ในการปิดเมนูที่เปิดอยู่ เมนูย่อยที่เปิดอยู่ หรือเมนูป๊อบอัพที่เปิดอยู่ ให้กดปุ่ม Esc

\n' + + '\n' + + '

หากโฟกัสปัจจุบันอยู่ที่ ‘ด้านบนสุด’ ของส่วน UI เฉพาะ การกดปุ่ม Esc จะทำให้ออกจาก\n' + + ' การนำทางด้วยแป้นพิมพ์ทั้งหมดเช่นกัน

\n' + + '\n' + + '

การดำเนินการรายการเมนูหรือปุ่มในแถบเครื่องมือ

\n' + + '\n' + + '

เมื่อไฮไลต์รายการเมนูหรือปุ่มในแถบเครื่องมือที่ต้องการ ให้กด Return, Enter\n' + + ' หรือ Space bar เพื่อดำเนินการรายการดังกล่าว

\n' + + '\n' + + '

การนำทางสำหรับกล่องโต้ตอบที่ไม่อยู่ในแท็บ

\n' + + '\n' + + '

ในกล่องโต้ตอบที่ไม่อยู่ในแท็บ จะโฟกัสที่ส่วนประกอบเชิงโต้ตอบแรกเมื่อกล่องโต้ตอบเปิด

\n' + + '\n' + + '

นำทางระหว่างส่วนประกอบเชิงโต้ตอบต่างๆ ของกล่องโต้ตอบ โดยการกด Tab หรือ Shift+Tab

\n' + + '\n' + + '

การนำทางสำหรับกล่องโต้ตอบที่อยู่ในแท็บ

\n' + + '\n' + + '

ในกล่องโต้ตอบที่อยู่ในแท็บ จะโฟกัสที่ปุ่มแรกในเมนูแท็บเมื่อกล่องโต้ตอบเปิด

\n' + + '\n' + + '

นำทางระหว่างส่วนประกอบเชิงโต้ตอบต่างๆ ของแท็บกล่องโต้ตอบนี้โดยการกด Tab หรือ\n' + + ' Shift+Tab

\n' + + '\n' + + '

สลับไปยังแท็บกล่องโต้ตอบอื่นโดยการเลือกโฟกัสที่เมนูแท็บ แล้วกดปุ่มลูกศรที่เหมาะสม\n' + + ' เพื่อเลือกแท็บที่ใช้ได้

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/tr.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/tr.js new file mode 100644 index 0000000..37f39b0 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/tr.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.tr', +'

Klavyeyle gezintiyi başlatma

\n' + + '\n' + + '
\n' + + '
Menü çubuğuna odaklan
\n' + + '
Windows veya Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Araç çubuğuna odaklan
\n' + + '
Windows veya Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Alt bilgiye odaklan
\n' + + '
Windows veya Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Bildirime odakla
\n' + + '
Windows veya Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Bağlamsal araç çubuğuna odaklan
\n' + + '
Windows, Linux veya macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Gezinti ilk kullanıcı arabirimi öğesinden başlar, bu öğe vurgulanır ya da ilk öğe, Alt bilgi elemanı\n' + + ' yolundaysa altı çizilir.

\n' + + '\n' + + '

Kullanıcı arabirimi bölümleri arasında gezinme

\n' + + '\n' + + '

Sonraki kullanıcı arabirimi bölümüne gitmek için Sekme tuşuna basın.

\n' + + '\n' + + '

Önceki kullanıcı arabirimi bölümüne gitmek için Shift+Sekme tuşlarına basın.

\n' + + '\n' + + '

Bu kullanıcı arabirimi bölümlerinin Sekme sırası:

\n' + + '\n' + + '
    \n' + + '
  1. Menü çubuğu
  2. \n' + + '
  3. Her araç çubuğu grubu
  4. \n' + + '
  5. Kenar çubuğu
  6. \n' + + '
  7. Alt bilgide öğe yolu
  8. \n' + + '
  9. Alt bilgide sözcük sayısı geçiş düğmesi
  10. \n' + + '
  11. Alt bilgide marka bağlantısı
  12. \n' + + '
  13. Alt bilgide düzenleyiciyi yeniden boyutlandırma tutamacı
  14. \n' + + '
\n' + + '\n' + + '

Kullanıcı arabirimi bölümü yoksa atlanır.

\n' + + '\n' + + '

Alt bilgide klavyeyle gezinti odağı yoksa ve görünür bir kenar çubuğu mevcut değilse Shift+Sekme tuşlarına basıldığında\n' + + ' odak son araç çubuğu yerine ilk araç çubuğu grubuna taşınır.

\n' + + '\n' + + '

Kullanıcı arabirimi bölümleri içinde gezinme

\n' + + '\n' + + '

Sonraki kullanıcı arabirimi elemanına gitmek için uygun Ok tuşuna basın.

\n' + + '\n' + + '

Sol ve Sağ ok tuşları

\n' + + '\n' + + '
    \n' + + '
  • menü çubuğundaki menüler arasında hareket eder.
  • \n' + + '
  • menüde bir alt menü açar.
  • \n' + + '
  • araç çubuğu grubundaki düğmeler arasında hareket eder.
  • \n' + + '
  • alt bilginin öğe yolundaki öğeler arasında hareket eder.
  • \n' + + '
\n' + + '\n' + + '

Aşağı ve Yukarı ok tuşları

\n' + + '\n' + + '
    \n' + + '
  • menüdeki menü öğeleri arasında hareket eder.
  • \n' + + '
  • araç çubuğu açılır menüsündeki öğeler arasında hareket eder.
  • \n' + + '
\n' + + '\n' + + '

Ok tuşları, odaklanılan kullanıcı arabirimi bölümü içinde döngüsel olarak hareket eder.

\n' + + '\n' + + '

Açık bir menüyü, açık bir alt menüyü veya açık bir açılır menüyü kapatmak için Esc tuşuna basın.

\n' + + '\n' + + '

Geçerli odak belirli bir kullanıcı arabirimi bölümünün "üst" kısmındaysa Esc tuşuna basıldığında\n' + + ' klavyeyle gezintiden de tamamen çıkılır.

\n' + + '\n' + + '

Menü öğesini veya araç çubuğu düğmesini yürütme

\n' + + '\n' + + '

İstediğiniz menü öğesi veya araç çubuğu düğmesi vurgulandığında Return, Enter\n' + + ' veya Ara çubuğu tuşuna basın.

\n' + + '\n' + + '

Sekme bulunmayan iletişim kutularında gezinme

\n' + + '\n' + + '

Sekme bulunmayan iletişim kutularında, iletişim kutusu açıldığında ilk etkileşimli bileşene odaklanılır.

\n' + + '\n' + + '

Etkileşimli iletişim kutusu bileşenleri arasında gezinmek için Sekme veya Shift+ Sekme tuşlarına basın.

\n' + + '\n' + + '

Sekmeli iletişim kutularında gezinme

\n' + + '\n' + + '

Sekmeli iletişim kutularında, iletişim kutusu açıldığında sekme menüsündeki ilk düğmeye odaklanılır.

\n' + + '\n' + + '

Bu iletişim kutusu sekmesinin etkileşimli bileşenleri arasında gezinmek için Sekme veya\n' + + ' Shift+Sekme tuşlarına basın.

\n' + + '\n' + + '

Mevcut sekmeler arasında geçiş yapmak için sekme menüsüne odaklanıp uygun Ok tuşuna basarak\n' + + ' başka bir iletişim kutusu sekmesine geçiş yapın.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/uk.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/uk.js new file mode 100644 index 0000000..028d4a4 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/uk.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.uk', +'

Початок роботи з навігацією за допомогою клавіатури

\n' + + '\n' + + '
\n' + + '
Фокус на рядок меню
\n' + + '
Windows або Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Фокус на панелі інструментів
\n' + + '
Windows або Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Фокус на розділі "Нижній колонтитул"
\n' + + '
Windows або Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Фокус на сповіщення
\n' + + '
Windows або Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Фокус на контекстній панелі інструментів
\n' + + '
Windows, Linux або macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Навігація почнеться з першого елемента інтерфейсу користувача, який буде виділено або підкреслено в разі, якщо перший елемент знаходиться в\n' + + ' шляху до елемента "Нижній колонтитул".

\n' + + '\n' + + '

Навігація між розділами інтерфейсу користувача

\n' + + '\n' + + '

Щоб перейти з одного розділу інтерфейсу користувача до наступного розділу, натисніть клавішу Tab.

\n' + + '\n' + + '

Щоб перейти з одного розділу інтерфейсу користувача до попереднього розділу, натисніть сполучення клавіш Shift+Tab.

\n' + + '\n' + + '

Порядок Вкладок цих розділів інтерфейсу користувача такий:

\n' + + '\n' + + '
    \n' + + '
  1. Рядок меню
  2. \n' + + '
  3. Кожна група панелей інструментів
  4. \n' + + '
  5. Бічна панель
  6. \n' + + '
  7. Шлях до елементів у розділі "Нижній колонтитул"
  8. \n' + + '
  9. Кнопка перемикача "Кількість слів" у розділі "Нижній колонтитул"
  10. \n' + + '
  11. Посилання на брендинг у розділі "Нижній колонтитул"
  12. \n' + + '
  13. Маркер змінення розміру в розділі "Нижній колонтитул"
  14. \n' + + '
\n' + + '\n' + + '

Якщо розділ інтерфейсу користувача відсутній, він пропускається.

\n' + + '\n' + + '

Якщо фокус навігації клавіатури знаходиться на розділі "Нижній колонтитул", але користувач не бачить видиму бічну панель, натисніть Shift+Tab,\n' + + ' щоб перемістити фокус на першу групу панелі інструментів, а не на останню.

\n' + + '\n' + + '

Навігація в межах розділів інтерфейсу користувача

\n' + + '\n' + + '

Щоб перейти з одного елементу інтерфейсу користувача до наступного, натисніть відповідну клавішу зі стрілкою.

\n' + + '\n' + + '

Клавіші зі стрілками Ліворуч і Праворуч

\n' + + '\n' + + '
    \n' + + '
  • переміщують між меню в рядку меню.
  • \n' + + '
  • відкривають вкладене меню в меню.
  • \n' + + '
  • переміщують користувача між кнопками в групі панелі інструментів.
  • \n' + + '
  • переміщують між елементами в шляху до елементів у розділі "Нижній колонтитул".
  • \n' + + '
\n' + + '\n' + + '

Клавіші зі стрілками Вниз і Вгору

\n' + + '\n' + + '
    \n' + + '
  • переміщують між елементами меню в меню.
  • \n' + + '
  • переміщують між елементами в спливаючому меню панелі інструментів.
  • \n' + + '
\n' + + '\n' + + '

Клавіші зі стрілками переміщують фокус циклічно в межах розділу інтерфейсу користувача, на якому знаходиться фокус.

\n' + + '\n' + + '

Щоб закрити відкрите меню, відкрите вкладене меню або відкрите спливаюче меню, натисніть клавішу Esc.

\n' + + '\n' + + '

Якщо поточний фокус знаходиться на верхньому рівні певного розділу інтерфейсу користувача, натискання клавіші Esc також виконує вихід\n' + + ' з навігації за допомогою клавіатури повністю.

\n' + + '\n' + + '

Виконання елементу меню або кнопки панелі інструментів

\n' + + '\n' + + '

Коли потрібний елемент меню або кнопку панелі інструментів виділено, натисніть клавіші Return, Enter,\n' + + ' або Пробіл, щоб виконати цей елемент.

\n' + + '\n' + + '

Навігація по діалоговим вікнам без вкладок

\n' + + '\n' + + '

У діалогових вікнах без вкладок перший інтерактивний компонент приймає фокус, коли відкривається діалогове вікно.

\n' + + '\n' + + '

Переходьте між інтерактивними компонентами діалогового вікна, натискаючи клавіші Tab або Shift+Tab.

\n' + + '\n' + + '

Навігація по діалоговим вікнам з вкладками

\n' + + '\n' + + '

У діалогових вікнах із вкладками перша кнопка в меню вкладки приймає фокус, коли відкривається діалогове вікно.

\n' + + '\n' + + '

Переходьте між інтерактивними компонентами цієї вкладки діалогового вікна, натискаючи клавіші Tab або\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Щоб перейти на іншу вкладку діалогового вікна, перемістіть фокус на меню вкладки, а потім натисніть відповідну клавішу зі стрілкою,\n' + + ' щоб циклічно переходити по доступним вкладкам.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/vi.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/vi.js new file mode 100644 index 0000000..d8eda11 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/vi.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.vi', +'

Bắt đầu điều hướng bàn phím

\n' + + '\n' + + '
\n' + + '
Tập trung vào thanh menu
\n' + + '
Windows hoặc Linux: Alt+F9
\n' + + '
macOS: ⌥F9
\n' + + '
Tập trung vào thanh công cụ
\n' + + '
Windows hoặc Linux: Alt+F10
\n' + + '
macOS: ⌥F10
\n' + + '
Tập trung vào chân trang
\n' + + '
Windows hoặc Linux: Alt+F11
\n' + + '
macOS: ⌥F11
\n' + + '
Tập trung vào thông báo
\n' + + '
Windows hoặc Linux: Alt+F12
\n' + + '
macOS: ⌥F12
\n' + + '
Tập trung vào thanh công cụ ngữ cảnh
\n' + + '
Windows, Linux hoặc macOS: Ctrl+F9
\n' + + '
\n' + + '\n' + + '

Điều hướng sẽ bắt đầu từ mục UI đầu tiên. Mục này sẽ được tô sáng hoặc có gạch dưới (nếu là mục đầu tiên trong\n' + + ' đường dẫn phần tử Chân trang).

\n' + + '\n' + + '

Di chuyển qua lại giữa các phần UI

\n' + + '\n' + + '

Để di chuyển từ một phần UI sang phần tiếp theo, ấn Tab.

\n' + + '\n' + + '

Để di chuyển từ một phần UI về phần trước đó, ấn Shift+Tab.

\n' + + '\n' + + '

Thứ tự Tab của các phần UI này như sau:

\n' + + '\n' + + '
    \n' + + '
  1. Thanh menu
  2. \n' + + '
  3. Từng nhóm thanh công cụ
  4. \n' + + '
  5. Thanh bên
  6. \n' + + '
  7. Đường dẫn phần tử trong chân trang
  8. \n' + + '
  9. Nút chuyển đổi đếm chữ ở chân trang
  10. \n' + + '
  11. Liên kết thương hiệu ở chân trang
  12. \n' + + '
  13. Núm điều tác chỉnh kích cỡ trình soạn thảo ở chân trang
  14. \n' + + '
\n' + + '\n' + + '

Nếu người dùng không thấy một phần UI, thì có nghĩa phần đó bị bỏ qua.

\n' + + '\n' + + '

Nếu ở chân trang có tính năng tập trung điều hướng bàn phím, mà không có thanh bên nào hiện hữu, thao tác ấn Shift+Tab\n' + + ' sẽ chuyển hướng tập trung vào nhóm thanh công cụ đầu tiên, không phải cuối cùng.

\n' + + '\n' + + '

Di chuyển qua lại trong các phần UI

\n' + + '\n' + + '

Để di chuyển từ một phần tử UI sang phần tiếp theo, ấn phím Mũi tên tương ứng cho phù hợp.

\n' + + '\n' + + '

Các phím mũi tên TráiPhải

\n' + + '\n' + + '
    \n' + + '
  • di chuyển giữa các menu trong thanh menu.
  • \n' + + '
  • mở menu phụ trong một menu.
  • \n' + + '
  • di chuyển giữa các nút trong nhóm thanh công cụ.
  • \n' + + '
  • di chuyển giữa các mục trong đường dẫn phần tử của chân trang.
  • \n' + + '
\n' + + '\n' + + '

Các phím mũi tên Hướng xuốngHướng lên

\n' + + '\n' + + '
    \n' + + '
  • di chuyển giữa các mục menu trong menu.
  • \n' + + '
  • di chuyển giữa các mục trong menu thanh công cụ dạng bật lên.
  • \n' + + '
\n' + + '\n' + + '

Các phím mũi tên xoay vòng trong một phần UI tập trung.

\n' + + '\n' + + '

Để đóng một menu mở, một menu phụ đang mở, hoặc một menu dạng bật lên đang mở, hãy ấn phím Esc.

\n' + + '\n' + + '

Nếu trọng tâm hiện tại là ở phần “đầu” của một phần UI cụ thể, thao tác ấn phím Esc cũng sẽ thoát\n' + + ' toàn bộ phần điều hướng bàn phím.

\n' + + '\n' + + '

Thực hiện chức năng của một mục menu hoặc nút thanh công cụ

\n' + + '\n' + + '

Khi mục menu hoặc nút thanh công cụ muốn dùng được tô sáng, hãy ấn Return, Enter,\n' + + ' hoặc Phím cách để thực hiện chức năng mục đó.

\n' + + '\n' + + '

Điều hướng giữa các hộp thoại không có nhiều tab

\n' + + '\n' + + '

Trong các hộp thoại không có nhiều tab, khi hộp thoại mở ra, trọng tâm sẽ hướng vào thành phần tương tác đầu tiên.

\n' + + '\n' + + '

Di chuyển giữa các thành phần hộp thoại tương tác bằng cách ấn Tab hoặc Shift+Tab.

\n' + + '\n' + + '

Điều hướng giữa các hộp thoại có nhiều tab

\n' + + '\n' + + '

Trong các hộp thoại có nhiều tab, khi hộp thoại mở ra, trọng tâm sẽ hướng vào nút đầu tiên trong menu tab.

\n' + + '\n' + + '

Di chuyển giữa các thành phần tương tác của tab hộp thoại này bằng cách ấn Tab hoặc\n' + + ' Shift+Tab.

\n' + + '\n' + + '

Chuyển sang một tab hộp thoại khác bằng cách chuyển trọng tâm vào menu tab, rồi ấn phím Mũi tên phù hợp\n' + + ' để xoay vòng các tab hiện có.

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_CN.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_CN.js new file mode 100644 index 0000000..f7e73d1 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_CN.js @@ -0,0 +1,87 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.zh_CN', +'

开始键盘导航

\n' + + '\n' + + '
\n' + + '
使菜单栏处于焦点
\n' + + '
Windows 或 Linux:Alt+F9
\n' + + '
macOS:⌥F9
\n' + + '
使工具栏处于焦点
\n' + + '
Windows 或 Linux:Alt+F10
\n' + + '
macOS:⌥F10
\n' + + '
使页脚处于焦点
\n' + + '
Windows 或 Linux:Alt+F11
\n' + + '
macOS:⌥F11
\n' + + '
使通知处于焦点
\n' + + '
Windows 或 Linux:Alt+F12
\n' + + '
macOS:⌥F12
\n' + + '
使上下文工具栏处于焦点
\n' + + '
Windows、Linux 或 macOS:Ctrl+F9
\n' + + '
\n' + + '\n' + + '

导航将在第一个 UI 项上开始,其中突出显示该项,或者对于页脚元素路径中的第一项,将为其添加下划线。

\n' + + '\n' + + '

在 UI 部分之间导航

\n' + + '\n' + + '

要从一个 UI 部分移至下一个,请按 Tab

\n' + + '\n' + + '

要从一个 UI 部分移至上一个,请按 Shift+Tab

\n' + + '\n' + + '

这些 UI 部分的 Tab 顺序为:

\n' + + '\n' + + '
    \n' + + '
  1. 菜单栏
  2. \n' + + '
  3. 每个工具栏组
  4. \n' + + '
  5. 边栏
  6. \n' + + '
  7. 页脚中的元素路径
  8. \n' + + '
  9. 页脚中的字数切换按钮
  10. \n' + + '
  11. 页脚中的品牌链接
  12. \n' + + '
  13. 页脚中的编辑器调整大小图柄
  14. \n' + + '
\n' + + '\n' + + '

如果不存在某个 UI 部分,则跳过它。

\n' + + '\n' + + '

如果键盘导航焦点在页脚,并且没有可见的边栏,则按 Shift+Tab 将焦点移至第一个工具栏组而非最后一个。

\n' + + '\n' + + '

在 UI 部分内导航

\n' + + '\n' + + '

要从一个 UI 元素移至下一个,请按相应的箭头键。

\n' + + '\n' + + '

箭头键

\n' + + '\n' + + '
    \n' + + '
  • 在菜单栏中的菜单之间移动。
  • \n' + + '
  • 打开菜单中的子菜单。
  • \n' + + '
  • 在工具栏组中的按钮之间移动。
  • \n' + + '
  • 在页脚的元素路径中的各项之间移动。
  • \n' + + '
\n' + + '\n' + + '

箭头键

\n' + + '\n' + + '
    \n' + + '
  • 在菜单中的菜单项之间移动。
  • \n' + + '
  • 在工具栏弹出菜单中的各项之间移动。
  • \n' + + '
\n' + + '\n' + + '

箭头键在具有焦点的 UI 部分内循环。

\n' + + '\n' + + '

要关闭打开的菜单、打开的子菜单或打开的弹出菜单,请按 Esc 键。

\n' + + '\n' + + '

如果当前的焦点在特定 UI 部分的“顶部”,则按 Esc 键还将完全退出键盘导航。

\n' + + '\n' + + '

执行菜单项或工具栏按钮

\n' + + '\n' + + '

当突出显示所需的菜单项或工具栏按钮时,按 ReturnEnter空格以执行该项。

\n' + + '\n' + + '

在非标签页式对话框中导航

\n' + + '\n' + + '

在非标签页式对话框中,当对话框打开时,第一个交互组件获得焦点。

\n' + + '\n' + + '

通过按 TabShift+Tab,在交互对话框组件之间导航。

\n' + + '\n' + + '

在标签页式对话框中导航

\n' + + '\n' + + '

在标签页式对话框中,当对话框打开时,标签页菜单中的第一个按钮获得焦点。

\n' + + '\n' + + '

通过按 TabShift+Tab,在此对话框的交互组件之间导航。

\n' + + '\n' + + '

通过将焦点移至另一对话框标签页的菜单,然后按相应的箭头键以在可用的标签页间循环,从而切换到该对话框标签页。

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_TW.js b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_TW.js new file mode 100644 index 0000000..5912770 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_TW.js @@ -0,0 +1,93 @@ +tinymce.Resource.add('tinymce.html-i18n.help-keynav.zh_TW', +'

開始鍵盤瀏覽

\n' + + '\n' + + '
\n' + + '
跳至功能表列
\n' + + '
Windows 或 Linux:Alt+F9
\n' + + '
macOS:⌥F9
\n' + + '
跳至工具列
\n' + + '
Windows 或 Linux:Alt+F10
\n' + + '
macOS:⌥F10
\n' + + '
跳至頁尾
\n' + + '
Windows 或 Linux:Alt+F11
\n' + + '
macOS:⌥F11
\n' + + '
跳至通知
\n' + + '
Windows 或 Linux:Alt+F12
\n' + + '
macOS:⌥F12
\n' + + '
跳至關聯式工具列
\n' + + '
Windows、Linux 或 macOS:Ctrl+F9
\n' + + '
\n' + + '\n' + + '

瀏覽會從第一個 UI 項目開始,該項目會反白顯示,但如果是「頁尾」元素路徑的第一項,\n' + + ' 則加底線。

\n' + + '\n' + + '

在 UI 區段之間瀏覽

\n' + + '\n' + + '

從 UI 區段移至下一個,請按 Tab

\n' + + '\n' + + '

從 UI 區段移回上一個,請按 Shift+Tab

\n' + + '\n' + + '

這些 UI 區段的 Tab 順序如下:

\n' + + '\n' + + '
    \n' + + '
  1. 功能表列
  2. \n' + + '
  3. 各個工具列群組
  4. \n' + + '
  5. 側邊欄
  6. \n' + + '
  7. 頁尾中的元素路徑
  8. \n' + + '
  9. 頁尾中字數切換按鈕
  10. \n' + + '
  11. 頁尾中的品牌連結
  12. \n' + + '
  13. 頁尾中編輯器調整大小控點
  14. \n' + + '
\n' + + '\n' + + '

如果 UI 區段未顯示,表示已略過該區段。

\n' + + '\n' + + '

如果鍵盤瀏覽跳至頁尾,但沒有顯示側邊欄,則按下 Shift+Tab\n' + + ' 會跳至第一個工具列群組,而不是最後一個。

\n' + + '\n' + + '

在 UI 區段之內瀏覽

\n' + + '\n' + + '

在兩個 UI 元素之間移動,請按適當的方向鍵。

\n' + + '\n' + + '

向左向右方向鍵

\n' + + '\n' + + '
    \n' + + '
  • 在功能表列中的功能表之間移動。
  • \n' + + '
  • 開啟功能表中的子功能表。
  • \n' + + '
  • 在工具列群組中的按鈕之間移動。
  • \n' + + '
  • 在頁尾的元素路徑中項目之間移動。
  • \n' + + '
\n' + + '\n' + + '

向下向上方向鍵

\n' + + '\n' + + '
    \n' + + '
  • 在功能表中的功能表項目之間移動。
  • \n' + + '
  • 在工具列快顯功能表中的項目之間移動。
  • \n' + + '
\n' + + '\n' + + '

方向鍵會在所跳至 UI 區段之內循環。

\n' + + '\n' + + '

若要關閉已開啟的功能表、已開啟的子功能表,或已開啟的快顯功能表,請按 Esc 鍵。

\n' + + '\n' + + '

如果目前已跳至特定 UI 區段的「頂端」,則按 Esc 鍵也會結束\n' + + ' 整個鍵盤瀏覽。

\n' + + '\n' + + '

執行功能表列項目或工具列按鈕

\n' + + '\n' + + '

當想要的功能表項目或工具列按鈕已反白顯示時,按 ReturnEnter、\n' + + ' 或空白鍵即可執行該項目。

\n' + + '\n' + + '

瀏覽非索引標籤式對話方塊

\n' + + '\n' + + '

在非索引標籤式對話方塊中,開啟對話方塊時會跳至第一個互動元件。

\n' + + '\n' + + '

TabShift+Tab 即可在互動式對話方塊元件之間瀏覽。

\n' + + '\n' + + '

瀏覽索引標籤式對話方塊

\n' + + '\n' + + '

在索引標籤式對話方塊中,開啟對話方塊時會跳至索引標籤式功能表中的第一個按鈕。

\n' + + '\n' + + '

若要在此對話方塊的互動式元件之間瀏覽,請按 Tab 或\n' + + ' Shift+Tab

\n' + + '\n' + + '

先跳至索引標籤式功能表,然後按適當的方向鍵,即可切換至另一個對話方塊索引標籤,\n' + + ' 以循環瀏覽可用的索引標籤。

\n'); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/help/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/help/plugin.min.js new file mode 100644 index 0000000..d211d6e --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/help/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const n=e=>{const n=(new Date).getTime(),a=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return t++,e+"_"+a+t+String(n)},a=e=>t=>t.options.get(e),r=a("help_tabs"),o=a("forced_plugins"),i=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=a=e,(r=String).prototype.isPrototypeOf(n)||(null===(o=a.constructor)||void 0===o?void 0:o.name)===r.name)?"string":t;var n,a,r,o})(e));const s=(void 0,e=>undefined===e);const l=e=>"function"==typeof e,m=(!1,()=>false);class c{constructor(e,t){this.tag=e,this.value=t}static some(e){return new c(!0,e)}static none(){return c.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?c.some(e(this.value)):c.none()}bind(e){return this.tag?e(this.value):c.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:c.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?c.none():c.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}c.singletonNone=new c(!1);const u=Array.prototype.slice,p=Array.prototype.indexOf,y=(e,t)=>{const n=e.length,a=new Array(n);for(let r=0;r{const n=[];for(let a=0,r=e.length;a{const n=u.call(e,0);return n.sort(t),n},g=Object.keys,k=Object.hasOwnProperty,v=(e,t)=>k.call(e,t);var b=tinymce.util.Tools.resolve("tinymce.Resource"),f=tinymce.util.Tools.resolve("tinymce.util.I18n");const A=(e,t)=>b.load(`tinymce.html-i18n.help-keynav.${t}`,`${e}/js/i18n/keynav/${t}.js`),w=e=>A(e,f.getCode()).catch((()=>A(e,"en")));var C=tinymce.util.Tools.resolve("tinymce.Env");const S=e=>{const t=C.os.isMacOS()||C.os.isiOS(),n=t?{alt:"⌥",ctrl:"⌃",shift:"⇧",meta:"⌘",access:"⌃⌥"}:{meta:"Ctrl ",access:"Shift + Alt "},a=e.split("+"),r=y(a,(e=>{const t=e.toLowerCase().trim();return v(n,t)?n[t]:e}));return t?r.join("").replace(/\s/,""):r.join("+")},M=[{shortcuts:["Meta + B"],action:"Bold"},{shortcuts:["Meta + I"],action:"Italic"},{shortcuts:["Meta + U"],action:"Underline"},{shortcuts:["Meta + A"],action:"Select all"},{shortcuts:["Meta + Y","Meta + Shift + Z"],action:"Redo"},{shortcuts:["Meta + Z"],action:"Undo"},{shortcuts:["Access + 1"],action:"Heading 1"},{shortcuts:["Access + 2"],action:"Heading 2"},{shortcuts:["Access + 3"],action:"Heading 3"},{shortcuts:["Access + 4"],action:"Heading 4"},{shortcuts:["Access + 5"],action:"Heading 5"},{shortcuts:["Access + 6"],action:"Heading 6"},{shortcuts:["Access + 7"],action:"Paragraph"},{shortcuts:["Access + 8"],action:"Div"},{shortcuts:["Access + 9"],action:"Address"},{shortcuts:["Alt + 0"],action:"Open help dialog"},{shortcuts:["Alt + F9"],action:"Focus to menubar"},{shortcuts:["Alt + F10"],action:"Focus to toolbar"},{shortcuts:["Alt + F11"],action:"Focus to element path"},{shortcuts:["Alt + F12"],action:"Focus to notification"},{shortcuts:["Ctrl + F9"],action:"Focus to contextual toolbar"},{shortcuts:["Shift + Enter"],action:"Open popup menu for split buttons"},{shortcuts:["Meta + K"],action:"Insert link (if link plugin activated)"},{shortcuts:["Meta + S"],action:"Save (if save plugin activated)"},{shortcuts:["Meta + F"],action:"Find (if searchreplace plugin activated)"},{shortcuts:["Meta + Shift + F"],action:"Switch to or from fullscreen mode"}],_=()=>({name:"shortcuts",title:"Handy Shortcuts",items:[{type:"table",header:["Action","Shortcut"],cells:y(M,(e=>{const t=y(e.shortcuts,S).join(" or ");return[e.action,t]}))}]}),x=y([{key:"accordion",name:"Accordion"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"image",name:"Image"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"advlist",name:"List Styles"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"pagebreak",name:"Page Break"},{key:"preview",name:"Preview"},{key:"quickbars",name:"Quick Toolbars"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"table",name:"Table"},{key:"textcolor",name:"Text Color"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"},{key:"a11ychecker",name:"Accessibility Checker",type:"premium"},{key:"typography",name:"Advanced Typography",type:"premium",slug:"advanced-typography"},{key:"ai",name:"AI Assistant",type:"premium"},{key:"casechange",name:"Case Change",type:"premium"},{key:"checklist",name:"Checklist",type:"premium"},{key:"advcode",name:"Enhanced Code Editor",type:"premium"},{key:"mediaembed",name:"Enhanced Media Embed",type:"premium",slug:"introduction-to-mediaembed"},{key:"advtable",name:"Enhanced Tables",type:"premium"},{key:"exportpdf",name:"Export to PDF",type:"premium"},{key:"exportword",name:"Export to Word",type:"premium"},{key:"footnotes",name:"Footnotes",type:"premium"},{key:"formatpainter",name:"Format Painter",type:"premium"},{key:"editimage",name:"Image Editing",type:"premium"},{key:"importword",name:"Import from Word",type:"premium"},{key:"inlinecss",name:"Inline CSS",type:"premium",slug:"inline-css"},{key:"linkchecker",name:"Link Checker",type:"premium"},{key:"math",name:"Math",type:"premium"},{key:"markdown",name:"Markdown",type:"premium"},{key:"mentions",name:"Mentions",type:"premium"},{key:"mergetags",name:"Merge Tags",type:"premium"},{key:"pageembed",name:"Page Embed",type:"premium"},{key:"permanentpen",name:"Permanent Pen",type:"premium"},{key:"powerpaste",name:"PowerPaste",type:"premium",slug:"introduction-to-powerpaste"},{key:"revisionhistory",name:"Revision History",type:"premium"},{key:"tinymcespellchecker",name:"Spell Checker",type:"premium",slug:"introduction-to-tiny-spellchecker"},{key:"autocorrect",name:"Spelling Autocorrect",type:"premium"},{key:"tableofcontents",name:"Table of Contents",type:"premium"},{key:"advtemplate",name:"Templates",type:"premium",slug:"advanced-templates"},{key:"tinycomments",name:"Tiny Comments",type:"premium",slug:"introduction-to-tiny-comments"},{key:"tinydrive",name:"Tiny Drive",type:"premium",slug:"tinydrive-introduction"}],(e=>({...e,type:e.type||"opensource",slug:e.slug||e.key}))),T=e=>{const t=e=>`${e.name}`,n=(e,n)=>{return(a=x,r=e=>e.key===n,((e,t,n)=>{for(let a=0,r=e.length;a((e,n)=>{const a=e.plugins[n].getMetadata;if(l(a)){const e=a();return{name:e.name,html:t(e)}}return{name:n,html:n}})(e,n)),(e=>{const n="premium"===e.type?`${e.name}*`:e.name;return{name:n,html:t({name:n,url:`https://www.tiny.cloud/docs/tinymce/7/${e.slug}/`})}}));var a,r},a=e=>{const t=(e=>{const t=g(e.plugins),n=o(e);return s(n)?t:h(t,(e=>!(((e,t)=>p.call(e,t))(n,e)>-1)))})(e),a=d(y(t,(t=>n(e,t))),((e,t)=>e.name.localeCompare(t.name))),r=y(a,(e=>"
  • "+e.html+"
  • ")),i=r.length,l=r.join("");return"

    "+f.translate(["Plugins installed ({0}):",i])+"

      "+l+"
    "},r={type:"htmlpanel",presets:"document",html:[(e=>null==e?"":"
    "+a(e)+"
    ")(e),(()=>{const e=h(x,(({type:e})=>"premium"===e)),t=d(y(e,(e=>e.name)),((e,t)=>e.localeCompare(t))),n=y(t,(e=>`
  • ${e}
  • `)).join("");return"

    "+f.translate("Premium plugins:")+"

    "})()].join("")};return{name:"plugins",title:"Plugins",items:[r]}};var O=tinymce.util.Tools.resolve("tinymce.EditorManager");const F=(e,t,a)=>()=>{(async(e,t,a)=>{const o=_(),s=await(async e=>({name:"keyboardnav",title:"Keyboard Navigation",items:[{type:"htmlpanel",presets:"document",html:await w(e)}]}))(a),l=T(e),m=(()=>{var e,t;const n='TinyMCE '+(e=O.majorVersion,t=O.minorVersion,(0===e.indexOf("@")?"X.X.X":e+"."+t)+"");return{name:"versions",title:"Version",items:[{type:"htmlpanel",html:"

    "+f.translate(["You are using {0}",n])+"

    ",presets:"document"}]}})(),u={[o.name]:o,[s.name]:s,[l.name]:l,[m.name]:m,...t.get()};return c.from(r(e)).fold((()=>(e=>{const t=g(e),n=t.indexOf("versions");return-1!==n&&(t.splice(n,1),t.push("versions")),{tabs:e,names:t}})(u)),(e=>((e,t)=>{const a={},r=y(e,(e=>{var r;if(i(e))return v(t,e)&&(a[e]=t[e]),e;{const t=null!==(r=e.name)&&void 0!==r?r:n("tab-name");return a[t]=e,t}}));return{tabs:a,names:r}})(e,u)))})(e,t,a).then((({tabs:t,names:n})=>{const a={type:"tabpanel",tabs:(e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t{return v(n=t,a=e)?c.from(n[a]):c.none();var n,a})))};e.windowManager.open({title:"Help",size:"medium",body:a,buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{}})}))};e.add("help",((e,t)=>{const a=(e=>{let t={};return{get:()=>t,set:e=>{t=e}}})(),r=(e=>({addTab:t=>{var a;const r=null!==(a=t.name)&&void 0!==a?a:n("tab-name"),o=e.get();o[r]=t,e.set(o)}}))(a);(e=>{(0,e.options.register)("help_tabs",{processor:"array"})})(e);const o=F(e,a,t);return((e,t)=>{e.ui.registry.addButton("help",{icon:"help",tooltip:"Help",onAction:t}),e.ui.registry.addMenuItem("help",{text:"Help",icon:"help",shortcut:"Alt+0",onAction:t})})(e,o),((e,t)=>{e.addCommand("mceHelp",t)})(e,o),e.shortcuts.add("Alt+0","Open help dialog","mceHelp"),((e,t)=>{e.on("init",(()=>{w(t)}))})(e,t),r}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/image/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/image/plugin.min.js new file mode 100644 index 0000000..01ae7ab --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/image/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=Object.getPrototypeOf,a=(e,t,a)=>{var i;return!!a(e,t.prototype)||(null===(i=e.constructor)||void 0===i?void 0:i.name)===t.name},i=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&a(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,s=e=>t=>typeof t===e,r=i("string"),o=i("object"),n=e=>((e,i)=>o(e)&&a(e,i,((e,a)=>t(e)===a)))(e,Object),l=i("array"),c=(null,e=>null===e);const m=s("boolean"),d=e=>!(e=>null==e)(e),g=s("function"),u=s("number"),p=()=>{};class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const b=Object.keys,v=Object.hasOwnProperty,y=(e,t)=>v.call(e,t),f=Array.prototype.push,w=e=>{const t=[];for(let a=0,i=e.length;a{((e,t,a)=>{if(!(r(a)||m(a)||u(a)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",a,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,a+"")})(e.dom,t,a)},D=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},_=D;var C=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),I=tinymce.util.Tools.resolve("tinymce.util.URI");const U=e=>e.length>0,x=e=>t=>t.options.get(e),S=x("image_dimensions"),N=x("image_advtab"),T=x("image_uploadtab"),O=x("image_prepend_url"),E=x("image_class_list"),L=x("image_description"),j=x("image_title"),M=x("image_caption"),R=x("image_list"),k=x("a11y_advanced_options"),z=x("automatic_uploads"),B=(e,t)=>Math.max(parseInt(e,10),parseInt(t,10)),P=e=>(e&&(e=e.replace(/px$/,"")),e),F=e=>(e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e),H=e=>"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder")),G=(e,t)=>{const a=e.options.get;return I.isDomSafe(t,"img",{allow_html_data_urls:a("allow_html_data_urls"),allow_script_urls:a("allow_script_urls"),allow_svg_data_urls:a("allow_svg_data_urls")})},W=C.DOM,$=e=>e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?P(e.style.marginLeft):"",V=e=>e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?P(e.style.marginTop):"",K=e=>e.style.borderWidth?P(e.style.borderWidth):"",Z=(e,t)=>{var a;return e.hasAttribute(t)&&null!==(a=e.getAttribute(t))&&void 0!==a?a:""},q=e=>null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName,J=(e,t,a)=>{""===a||null===a?e.removeAttribute(t):e.setAttribute(t,a)},Q=(e,t)=>{const a=e.getAttribute("style"),i=t(null!==a?a:"");i.length>0?(e.setAttribute("style",i),e.setAttribute("data-mce-style",i)):e.removeAttribute("style")},X=(e,t)=>(e,a,i)=>{const s=e.style;s[a]?(s[a]=F(i),Q(e,t)):J(e,a,i)},Y=(e,t)=>e.style[t]?P(e.style[t]):Z(e,t),ee=(e,t)=>{const a=F(t);e.style.marginLeft=a,e.style.marginRight=a},te=(e,t)=>{const a=F(t);e.style.marginTop=a,e.style.marginBottom=a},ae=(e,t)=>{const a=F(t);e.style.borderWidth=a},ie=(e,t)=>{e.style.borderStyle=t},se=e=>{var t;return null!==(t=e.style.borderStyle)&&void 0!==t?t:""},re=e=>d(e)&&"FIGURE"===e.nodeName,oe=e=>0===W.getAttrib(e,"alt").length&&"presentation"===W.getAttrib(e,"role"),ne=e=>oe(e)?"":Z(e,"alt"),le=(e,t)=>{var a;const i=document.createElement("img");return J(i,"style",t.style),($(i)||""!==t.hspace)&&ee(i,t.hspace),(V(i)||""!==t.vspace)&&te(i,t.vspace),(K(i)||""!==t.border)&&ae(i,t.border),(se(i)||""!==t.borderStyle)&&ie(i,t.borderStyle),e(null!==(a=i.getAttribute("style"))&&void 0!==a?a:"")},ce=(e,t)=>({src:Z(t,"src"),alt:ne(t),title:Z(t,"title"),width:Y(t,"width"),height:Y(t,"height"),class:Z(t,"class"),style:e(Z(t,"style")),caption:q(t),hspace:$(t),vspace:V(t),border:K(t),borderStyle:se(t),isDecorative:oe(t)}),me=(e,t,a,i,s)=>{a[i]!==t[i]&&s(e,i,String(a[i]))},de=(e,t,a)=>{if(a){W.setAttrib(e,"role","presentation");const t=_(e);A(t,"alt","")}else{if(c(t)){"alt",_(e).dom.removeAttribute("alt")}else{const a=_(e);A(a,"alt",t)}"presentation"===W.getAttrib(e,"role")&&W.setAttrib(e,"role","")}},ge=(e,t)=>(a,i,s)=>{e(a,s),Q(a,t)},ue=(e,t,a)=>{const i=ce(e,a);me(a,i,t,"caption",((e,t,a)=>(e=>{q(e)?(e=>{const t=e.parentNode;d(t)&&(W.insertAfter(e,t),W.remove(t))})(e):(e=>{const t=W.create("figure",{class:"image"});W.insertAfter(t,e),t.appendChild(e),t.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"})(e)})(e))),me(a,i,t,"src",J),me(a,i,t,"title",J),me(a,i,t,"width",X(0,e)),me(a,i,t,"height",X(0,e)),me(a,i,t,"class",J),me(a,i,t,"style",ge(((e,t)=>J(e,"style",t)),e)),me(a,i,t,"hspace",ge(ee,e)),me(a,i,t,"vspace",ge(te,e)),me(a,i,t,"border",ge(ae,e)),me(a,i,t,"borderStyle",ge(ie,e)),((e,t,a)=>{a.alt===t.alt&&a.isDecorative===t.isDecorative||de(e,a.alt,a.isDecorative)})(a,i,t)},pe=(e,t)=>{const a=(e=>{if(e.margin){const t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e})(e.dom.styles.parse(t)),i=e.dom.styles.parse(e.dom.styles.serialize(a));return e.dom.styles.serialize(i)},he=e=>{const t=e.selection.getNode(),a=e.dom.getParent(t,"figure.image");return a?e.dom.select("img",a)[0]:t&&("IMG"!==t.nodeName||H(t))?null:t},be=(e,t)=>{var a;const i=e.dom,s=((t,a)=>{const i={};var s;return((e,t,a,i)=>{((e,t)=>{const a=b(e);for(let i=0,s=a.length;i{(t(e,s)?a:i)(e,s)}))})(t,((t,a)=>!e.schema.isValidChild(a,"figure")),(s=i,(e,t)=>{s[t]=e}),p),i})(e.schema.getTextBlockElements()),r=i.getParent(t.parentNode,(e=>{return t=s,a=e.nodeName,y(t,a)&&void 0!==t[a]&&null!==t[a];var t,a}),e.getBody());return r&&null!==(a=i.split(r,t))&&void 0!==a?a:t},ve=(e,t)=>{const a=((t,a)=>{const i=document.createElement("img");if(ue((t=>pe(e,t)),{...a,caption:!1},i),de(i,a.alt,a.isDecorative),a.caption){const e=W.create("figure",{class:"image"});return e.appendChild(i),e.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),e.contentEditable="false",e}return i})(0,t);e.dom.setAttrib(a,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(a.outerHTML);const i=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(i,"data-mce-id",null),re(i)){const t=be(e,i);e.selection.select(t)}else e.selection.select(i)},ye=(e,t)=>{const a=he(e);if(a){const i={...ce((t=>pe(e,t)),a),...t},s=((e,t)=>{const a=t.src;return{...t,src:G(e,a)?a:""}})(e,i);i.src?((e,t)=>{const a=he(e);if(a)if(ue((t=>pe(e,t)),t,a),((e,t)=>{e.dom.setAttrib(t,"src",t.getAttribute("src"))})(e,a),re(a.parentNode)){const t=a.parentNode;be(e,t),e.selection.select(a.parentNode)}else e.selection.select(a),((e,t,a)=>{const i=()=>{a.onload=a.onerror=null,e.selection&&(e.selection.select(a),e.nodeChanged())};a.onload=()=>{t.width||t.height||!S(e)||e.dom.setAttribs(a,{width:String(a.clientWidth),height:String(a.clientHeight)}),i()},a.onerror=i})(e,t,a)})(e,s):((e,t)=>{if(t){const a=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(a),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}})(e,a)}else t.src&&ve(e,{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1,...t})},fe=(we=(e,t)=>n(e)&&n(t)?fe(e,t):t,(...e)=>{if(0===e.length)throw new Error("Can't merge zero objects");const t={};for(let a=0;ar(e.value)?e.value:"",Ce=(e,t)=>{const a=[];return De.each(e,(e=>{const i=(e=>r(e.text)?e.text:r(e.title)?e.title:"")(e);if(void 0!==e.menu){const s=Ce(e.menu,t);a.push({text:i,items:s})}else{const s=t(e);a.push({text:i,value:s})}})),a},Ie=(e=_e)=>t=>t?h.from(t).map((t=>Ce(t,e))):h.none(),Ue=(e,t)=>((e,a)=>{for(let a=0;ay(e,"items"))(i=e[a])?Ue(i.items,t):i.value===t?h.some(i):h.none();if(s.isSome())return s}var i;return h.none()})(e),xe=Ie,Se=(e,t)=>e.bind((e=>Ue(e,t))),Ne=e=>{const t=xe((t=>e.convertURL(t.value||t.url||"","src"))),a=new Promise((a=>{((e,t)=>{const a=R(e);r(a)?fetch(a).then((e=>{e.ok&&e.json().then(t)})):g(a)?a(t):t(a)})(e,(e=>{a(t(e).map((e=>w([[{text:"None",value:""}],e]))))}))})),i=(A=E(e),Ie(_e)(A)),s=N(e),o=T(e),n=(e=>U(e.options.get("images_upload_url")))(e),l=(e=>d(e.options.get("images_upload_handler")))(e),c=(e=>{const t=he(e);return t?ce((t=>pe(e,t)),t):{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}})(e),m=L(e),u=j(e),p=S(e),b=M(e),v=k(e),y=z(e),f=h.some(O(e)).filter((e=>r(e)&&e.length>0));var A;return a.then((e=>({image:c,imageList:e,classList:i,hasAdvTab:s,hasUploadTab:o,hasUploadUrl:n,hasUploadHandler:l,hasDescription:m,hasImageTitle:u,hasDimensions:p,hasImageCaption:b,prependURL:f,hasAccessibilityOptions:v,automaticUploads:y})))},Te=e=>{const t=e.imageList.map((e=>({name:"images",type:"listbox",label:"Image list",items:e}))),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},i=e.classList.map((e=>({name:"classes",type:"listbox",label:"Class",items:e})));return w([[{name:"src",type:"urlinput",filetype:"image",label:"Source",picker_text:"Browse files"}],t.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[{...(s=e.classList.isSome()&&e.hasImageCaption,s?{type:"grid",columns:2}:{type:"panel"}),items:w([i.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])}]]);var s},Oe=e=>({title:"General",name:"general",items:Te(e)}),Ee=Te,Le=e=>({src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative}),je=(e,t)=>({src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative}),Me=(e,t,a,i)=>{((e,t)=>{const a=t.getData();((e,t)=>/^(?:[a-zA-Z]+:)?\/\//.test(t)?h.none():e.prependURL.bind((e=>t.substring(0,e.length)!==e?h.some(e+t):h.none())))(e,a.src.value).each((e=>{t.setData({src:{value:e,meta:a.src.meta}})}))})(t,i),((e,t)=>{const a=t.getData(),i=a.src.meta;if(void 0!==i){const s=fe({},a);((e,t,a)=>{e.hasDescription&&r(a.alt)&&(t.alt=a.alt),e.hasAccessibilityOptions&&(t.isDecorative=a.isDecorative||t.isDecorative||!1),e.hasImageTitle&&r(a.title)&&(t.title=a.title),e.hasDimensions&&(r(a.width)&&(t.dimensions.width=a.width),r(a.height)&&(t.dimensions.height=a.height)),r(a.class)&&Se(e.classList,a.class).each((e=>{t.classes=e.value})),e.hasImageCaption&&m(a.caption)&&(t.caption=a.caption),e.hasAdvTab&&(r(a.style)&&(t.style=a.style),r(a.vspace)&&(t.vspace=a.vspace),r(a.border)&&(t.border=a.border),r(a.hspace)&&(t.hspace=a.hspace),r(a.borderstyle)&&(t.borderstyle=a.borderstyle))})(e,s,i),t.setData(s)}})(t,i),((e,t,a,i)=>{const s=i.getData(),r=s.src.value,o=s.src.meta||{};o.width||o.height||!t.hasDimensions||(U(r)?e.imageSize(r).then((e=>{a.open&&i.setData({dimensions:e})})).catch((e=>console.error(e))):i.setData({dimensions:{width:"",height:""}}))})(e,t,a,i),((e,t,a)=>{const i=a.getData(),s=Se(e.imageList,i.src.value);t.prevImage=s,a.setData({images:s.map((e=>e.value)).getOr("")})})(t,a,i)},Re=(e,t,a,i)=>{const s=i.getData();var r;i.block("Uploading image"),(r=s.fileinput,((e,t)=>0{i.unblock()}),(s=>{const r=URL.createObjectURL(s),o=()=>{i.unblock(),URL.revokeObjectURL(r)},n=s=>{i.setData({src:{value:s,meta:{}}}),i.showTab("general"),Me(e,t,a,i),i.focus("src")};var l;(l=s,new Promise(((e,t)=>{const a=new FileReader;a.onload=()=>{e(a.result)},a.onerror=()=>{var e;t(null===(e=a.error)||void 0===e?void 0:e.message)},a.readAsDataURL(l)}))).then((a=>{const l=e.createBlobCache(s,r,a);t.automaticUploads?e.uploadImage(l).then((e=>{n(e.url),o()})).catch((t=>{o(),e.alertErr(t)})):(e.addToBlobCache(l),n(l.blobUri()),i.unblock())}))}))},ke=(e,t,a)=>(i,s)=>{"src"===s.name?Me(e,t,a,i):"images"===s.name?((e,t,a,i)=>{const s=i.getData(),r=Se(t.imageList,s.images);r.each((e=>{const t=""===s.alt||a.prevImage.map((e=>e.text===s.alt)).getOr(!1);t?""===e.value?i.setData({src:e,alt:a.prevAlt}):i.setData({src:e,alt:e.text}):i.setData({src:e})})),a.prevImage=r,Me(e,t,a,i)})(e,t,a,i):"alt"===s.name?a.prevAlt=i.getData().alt:"fileinput"===s.name?Re(e,t,a,i):"isDecorative"===s.name&&i.setEnabled("alt",!i.getData().isDecorative)},ze=e=>()=>{e.open=!1},Be=e=>e.hasAdvTab||e.hasUploadUrl||e.hasUploadHandler?{type:"tabpanel",tabs:w([[Oe(e)],e.hasAdvTab?[{title:"Advanced",name:"advanced",items:[{type:"grid",columns:2,items:[{type:"input",label:"Vertical space",name:"vspace",inputMode:"numeric"},{type:"input",label:"Horizontal space",name:"hspace",inputMode:"numeric"},{type:"input",label:"Border width",name:"border",inputMode:"numeric"},{type:"listbox",name:"borderstyle",label:"Border style",items:[{text:"Select...",value:""},{text:"Solid",value:"solid"},{text:"Dotted",value:"dotted"},{text:"Dashed",value:"dashed"},{text:"Double",value:"double"},{text:"Groove",value:"groove"},{text:"Ridge",value:"ridge"},{text:"Inset",value:"inset"},{text:"Outset",value:"outset"},{text:"None",value:"none"},{text:"Hidden",value:"hidden"}]}]}]}]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}]:[]])}:{type:"panel",items:Ee(e)},Pe=(e,t,a)=>i=>{const s=fe(Le(t.image),i.getData()),r={...s,style:le(a.normalizeCss,je(s,!1))};e.execCommand("mceUpdateImage",!1,je(r,t.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),i.close()},Fe=e=>t=>G(e,t)?(e=>new Promise((t=>{const a=document.createElement("img"),i=e=>{a.onload=a.onerror=null,a.parentNode&&a.parentNode.removeChild(a),t(e)};a.onload=()=>{const e={width:B(a.width,a.clientWidth),height:B(a.height,a.clientHeight)};i(Promise.resolve(e))},a.onerror=()=>{i(Promise.reject(`Failed to get image dimensions for: ${e}`))};const s=a.style;s.visibility="hidden",s.position="fixed",s.bottom=s.left="0px",s.width=s.height="auto",document.body.appendChild(a),a.src=e})))(e.documentBaseURI.toAbsolute(t)).then((e=>({width:String(e.width),height:String(e.height)}))):Promise.resolve({width:"",height:""}),He=e=>(t,a,i)=>{var s;return e.editorUpload.blobCache.create({blob:t,blobUri:a,name:null===(s=t.name)||void 0===s?void 0:s.replace(/\.[^\.]+$/,""),filename:t.name,base64:i.split(",")[1]})},Ge=e=>t=>{e.editorUpload.blobCache.add(t)},We=e=>t=>{e.windowManager.alert(t)},$e=e=>t=>pe(e,t),Ve=e=>t=>e.dom.parseStyle(t),Ke=e=>(t,a)=>e.dom.serializeStyle(t,a),Ze=e=>t=>Ae(e).upload([t],!1).then((e=>{var t;return 0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(null===(t=e[0].error)||void 0===t?void 0:t.message):e[0]})),qe=e=>{const t={imageSize:Fe(e),addToBlobCache:Ge(e),createBlobCache:He(e),alertErr:We(e),normalizeCss:$e(e),parseStyle:Ve(e),serializeStyle:Ke(e),uploadImage:Ze(e)};return{open:()=>{Ne(e).then((a=>{const i=(e=>({prevImage:Se(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}))(a);return{title:"Insert/Edit Image",size:"normal",body:Be(a),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:Le(a.image),onSubmit:Pe(e,a,t),onChange:ke(t,a,i),onClose:ze(i)}})).then(e.windowManager.open)}}},Je=e=>{const t=e.attr("class");return d(t)&&/\bimage\b/.test(t)},Qe=e=>t=>{let a=t.length;const i=t=>{t.attr("contenteditable",e?"true":null)};for(;a--;){const s=t[a];Je(s)&&(s.attr("contenteditable",e?"false":null),De.each(s.getAll("figcaption"),i))}},Xe=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("image",(e=>{(e=>{const t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:e=>{const t=!1===e||r(e)||((e,t)=>{if(l(e)){for(let a=0,i=e.length;a{e.on("PreInit",(()=>{e.parser.addNodeFilter("figure",Qe(!0)),e.serializer.addNodeFilter("figure",Qe(!1))}))})(e),(e=>{e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:qe(e).open,onSetup:t=>{t.setActive(d(he(e)));const a=e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind,i=Xe(e)(t);return()=>{a(),i()}}}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:qe(e).open,onSetup:Xe(e)}),e.ui.registry.addContextMenu("image",{update:t=>e.selection.isEditable()&&(re(t)||"IMG"===t.nodeName&&!H(t))?["image"]:[]})})(e),(e=>{e.addCommand("mceImage",qe(e).open),e.addCommand("mceUpdateImage",((t,a)=>{e.undoManager.transact((()=>ye(e,a)))}))})(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/importcss/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/importcss/plugin.min.js new file mode 100644 index 0000000..133e772 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/importcss/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),g=p("importcss_file_filter"),_=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),M=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s{const s=e.length,r=new Array(s);for(let o=0;oa.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=_(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/",c=e.editorManager.suffix;return t===o+"/content"+(e.inline?".inline":"")+`${c}.css`||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet&&e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(g(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),M(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/insertdatetime/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/insertdatetime/plugin.min.js new file mode 100644 index 0000000..c6a9b04 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/insertdatetime/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),n=t("insertdatetime_timeformat"),r=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let n;n=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const r=e.dom.getParent(e.selection.getStart(),"time");r?((e,t,a,n)=>{const r=e.dom.create("time",{datetime:a},n);e.dom.replace(r,t),e.selection.select(r,!0),e.selection.collapse(!1)})(e,r,n,a):e.insertContent('")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");const g=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,n)=>{u(e,null!=n?n:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:n(e))}))})(e),(e=>{const t=r(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=r(e);return t.length>0?t[0]:n(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)},onSetup:g(e)});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)}))),onSetup:g(e)})})(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/link/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/link/plugin.min.js new file mode 100644 index 0000000..21662fb --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/link/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(l=o.constructor)||void 0===l?void 0:l.name)===r.name)?"string":t;var n,o,r,l})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),l=t("array"),s=(null,e=>null===e);const a=n("boolean"),i=e=>!(e=>null==e)(e),c=n("function"),u=(e,t)=>{if(l(e)){for(let n=0,o=e.length;n{},d=(e,t)=>e===t;class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return i(e)?m.some(e):m.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const h=Array.prototype.indexOf,p=Array.prototype.push,f=e=>{const t=[];for(let n=0,o=e.length;n{for(let n=0;ne.exists((e=>n(e,t))),x=e=>{const t=[],n=e=>{t.push(e)};for(let t=0;te?m.some(t):m.none(),b=e=>t=>t.options.get(e),_=b("link_assume_external_targets"),w=b("link_context_toolbar"),C=b("link_list"),O=b("link_default_target"),S=b("link_default_protocol"),N=b("link_target_list"),A=b("link_rel_list"),T=b("link_class_list"),E=b("link_title"),L=b("allow_unsafe_link_target"),R=b("link_quicklink"),P=Object.keys,M=Object.hasOwnProperty,D=(e,t)=>M.call(e,t);var B=tinymce.util.Tools.resolve("tinymce.util.URI"),I=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),K=tinymce.util.Tools.resolve("tinymce.util.Tools");const j=e=>i(e)&&"a"===e.nodeName.toLowerCase(),U=e=>j(e)&&!!V(e),q=(e,t)=>{if(e.collapsed)return[];{const n=e.cloneContents(),o=n.firstChild,r=new I(o,n),l=[];let s=o;do{t(s)&&l.push(s)}while(s=r.next());return l}},F=e=>/^\w+:/i.test(e),V=e=>{var t,n;return null!==(n=null!==(t=e.getAttribute("data-mce-href"))&&void 0!==t?t:e.getAttribute("href"))&&void 0!==n?n:""},$=(e,t)=>{const n=["noopener"],o=e?e.split(/\s+/):[],r=e=>e.filter((e=>-1===K.inArray(n,e))),l=t?(e=>(e=r(e)).length>0?e.concat(n):n)(o):r(o);return l.length>0?(e=>K.trim(e.sort().join(" ")))(l):""},z=(e,t)=>(t=t||J(e.selection.getRng())[0]||e.selection.getNode(),Y(t)?m.from(e.dom.select("a[href]",t)[0]):m.from(e.dom.getParent(t,"a[href]"))),G=(e,t)=>z(e,t).isSome(),H=(e,t)=>t.fold((()=>e.getContent({format:"text"})),(e=>e.innerText||e.textContent||"")).replace(/\uFEFF/g,""),J=e=>q(e,U),W=e=>K.grep(e,U),Q=e=>W(e).length>0,X=e=>{const t=e.schema.getTextInlineElements();if(z(e).exists((e=>e.hasAttribute("data-mce-block"))))return!1;const n=e.selection.getRng();return!!n.collapsed||0===q(n,(e=>1===e.nodeType&&!j(e)&&!D(t,e.nodeName.toLowerCase()))).length},Y=e=>i(e)&&"FIGURE"===e.nodeName&&/\bimage\b/i.test(e.className),Z=(e,t,n)=>{const o=e.selection.getNode(),r=z(e,o),l=((e,t)=>{const n={...t};if(0===A(e).length&&!L(e)){const e=$(n.rel,"_blank"===n.target);n.rel=e||null}return m.from(n.target).isNone()&&!1===N(e)&&(n.target=O(e)),n.href=((e,t)=>"http"!==t&&"https"!==t||F(e)?e:t+"://"+e)(n.href,_(e)),n})(e,(e=>{return t=["title","rel","class","target"],n=(t,n)=>(e[n].each((e=>{t[n]=e.length>0?e:null})),t),o={href:e.href},((e,t)=>{for(let n=0,o=e.length;n{o=n(o,e)})),o;var t,n,o})(n));e.undoManager.transact((()=>{n.href===t.href&&t.attach(),r.fold((()=>{((e,t,n,o)=>{const r=e.dom;Y(t)?re(r,t,o):n.fold((()=>{e.execCommand("mceInsertLink",!1,o)}),(t=>{e.insertContent(r.createHTML("a",o,r.encode(t)))}))})(e,o,n.text,l)}),(t=>{e.focus(),((e,t,n,o)=>{n.each((e=>{D(t,"innerText")?t.innerText=e:t.textContent=e})),e.dom.setAttribs(t,o),e.selection.select(t)})(e,t,n.text,l)}))}))},ee=e=>{const{class:t,href:n,rel:o,target:r,text:l,title:a}=e;return((e,t)=>{const n={};var o;return((e,t,n,o)=>{((e,t)=>{const n=P(e);for(let o=0,r=n.length;o{(t(e,r)?n:o)(e,r)}))})(e,((e,t)=>!1===s(e)),(o=n,(e,t)=>{o[t]=e}),g),n})({class:t.getOrNull(),href:n,rel:o.getOrNull(),target:r.getOrNull(),text:l.getOrNull(),title:a.getOrNull()})},te=(e,t,n)=>{const o=((e,t)=>{const n=e.options.get,o={allow_html_data_urls:n("allow_html_data_urls"),allow_script_urls:n("allow_script_urls"),allow_svg_data_urls:n("allow_svg_data_urls")},r=t.href;return{...t,href:B.isDomSafe(r,"a",o)?r:""}})(e,n);e.hasPlugin("rtc",!0)?e.execCommand("createlink",!1,ee(o)):Z(e,t,o)},ne=e=>{e.hasPlugin("rtc",!0)?e.execCommand("unlink"):(e=>{e.undoManager.transact((()=>{const t=e.selection.getNode();Y(t)?oe(e,t):(e=>{const t=e.dom,n=e.selection,o=n.getBookmark(),r=n.getRng().cloneRange(),l=t.getParent(r.startContainer,"a[href]",e.getBody()),s=t.getParent(r.endContainer,"a[href]",e.getBody());l&&r.setStartBefore(l),s&&r.setEndAfter(s),n.setRng(r),e.execCommand("unlink"),n.moveToBookmark(o)})(e),e.focus()}))})(e)},oe=(e,t)=>{var n;const o=e.dom.select("img",t)[0];if(o){const r=e.dom.getParents(o,"a[href]",t)[0];r&&(null===(n=r.parentNode)||void 0===n||n.insertBefore(o,r),e.dom.remove(r))}},re=(e,t,n)=>{var o;const r=e.select("img",t)[0];if(r){const t=e.create("a",n);null===(o=r.parentNode)||void 0===o||o.insertBefore(t,r),t.appendChild(r)}},le=e=>o(e.value)?e.value:"",se=(e,t)=>{const n=[];return K.each(e,(e=>{const r=(e=>o(e.text)?e.text:o(e.title)?e.title:"")(e);if(void 0!==e.menu){const o=se(e.menu,t);n.push({text:r,items:o})}else{const o=t(e);n.push({text:r,value:o})}})),n},ae=(e=le)=>t=>m.from(t).map((t=>se(t,e))),ie=e=>ae(le)(e),ce=ae,ue=(e,t)=>n=>({name:e,type:"listbox",label:t,items:n}),ge=le,de=(e,t)=>k(t,(t=>(e=>{return D(t=e,n="items")&&void 0!==t[n]&&null!==t[n];var t,n})(t)?de(e,t.items):y(t.value===e,t))),me=(e,t)=>{const n={text:e.text,title:e.title},o=(e,o)=>{const r=(l=t,s=o,"link"===s?l.link:"anchor"===s?l.anchor:m.none()).getOr([]);var l,s;return((e,t,n,o)=>{const r=o[t],l=e.length>0;return void 0!==r?de(r,n).map((t=>({url:{value:t.value,meta:{text:l?e:t.text,attach:g}},text:l?e:t.text}))):m.none()})(n.text,o,r,e)};return{onChange:(e,t)=>{const r=t.name;return"url"===r?(e=>{const t=(o=e.url,y(n.text.length<=0,m.from(null===(r=o.meta)||void 0===r?void 0:r.text).getOr(o.value)));var o,r;const l=(e=>{var t;return y(n.title.length<=0,m.from(null===(t=e.meta)||void 0===t?void 0:t.title).getOr(""))})(e.url);return t.isSome()||l.isSome()?m.some({...t.map((e=>({text:e}))).getOr({}),...l.map((e=>({title:e}))).getOr({})}):m.none()})(e()):((e,t)=>h.call(e,t))(["anchor","link"],r)>-1?o(e(),r):"text"===r||"title"===r?(n[r]=e()[r],m.none()):m.none()}}};var he=tinymce.util.Tools.resolve("tinymce.util.Delay");const pe=e=>{const t=e.href;return t.indexOf("@")>0&&-1===t.indexOf("/")&&-1===t.indexOf("mailto:")?m.some({message:"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",preprocess:e=>({...e,href:"mailto:"+t})}):m.none()},fe=(e,t)=>n=>{const o=n.href;return 1===e&&!F(o)||0===e&&/^\s*www(\.|\d\.)/i.test(o)?m.some({message:`The URL you entered seems to be an external link. Do you want to add the required ${t}:// prefix?`,preprocess:e=>({...e,href:t+"://"+o})}):m.none()},ke=e=>{const t=e.dom.select("a:not([href])"),n=f(((e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r{const t=e.name||e.id;return t?[{text:t,value:"#"+t}]:[]})));return n.length>0?m.some([{text:"None",value:""}].concat(n)):m.none()},ve=e=>{const t=T(e);return t.length>0?ie(t):m.none()},xe=e=>{try{return m.some(JSON.parse(e))}catch(e){return m.none()}},ye=(e,t)=>{const n=A(e);if(n.length>0){const o=v(t,"_blank"),r=e=>$(ge(e),o);return(!1===L(e)?ce(r):ie)(n)}return m.none()},be=[{text:"Current window",value:""},{text:"New window",value:"_blank"}],_e=e=>{const t=N(e);return l(t)?ie(t).orThunk((()=>m.some(be))):!1===t?m.none():m.some(be)},we=(e,t,n)=>{const o=e.getAttrib(t,n);return null!==o&&o.length>0?m.some(o):m.none()},Ce=(e,t)=>(e=>{const t=t=>e.convertURL(t.value||t.url||"","href"),n=C(e);return new Promise((e=>{o(n)?fetch(n).then((e=>e.ok?e.text().then(xe):Promise.reject())).then(e,(()=>e(m.none()))):c(n)?n((t=>e(m.some(t)))):e(m.from(n))})).then((e=>e.bind(ce(t)).map((e=>e.length>0?[{text:"None",value:""}].concat(e):e))))})(e).then((n=>{const o=((e,t)=>{const n=e.dom,o=X(e)?m.some(H(e.selection,t)):m.none(),r=t.bind((e=>m.from(n.getAttrib(e,"href")))),l=t.bind((e=>m.from(n.getAttrib(e,"target")))),s=t.bind((e=>we(n,e,"rel"))),a=t.bind((e=>we(n,e,"class")));return{url:r,text:o,title:t.bind((e=>we(n,e,"title"))),target:l,rel:s,linkClass:a}})(e,t);return{anchor:o,catalogs:{targets:_e(e),rels:ye(e,o.target),classes:ve(e),anchor:ke(e),link:n},optNode:t,flags:{titleEnabled:E(e)}}})),Oe=e=>{const t=(e=>{const t=z(e);return Ce(e,t)})(e);t.then((t=>{const n=((e,t)=>n=>{const o=n.getData();if(!o.url.value)return ne(e),void n.close();const r=e=>m.from(o[e]).filter((n=>!v(t.anchor[e],n))),l={href:o.url.value,text:r("text"),target:r("target"),rel:r("rel"),class:r("linkClass"),title:r("title")},s={href:o.url.value,attach:void 0!==o.url.meta&&o.url.meta.attach?o.url.meta.attach:g};((e,t)=>k([pe,fe(_(e),S(e))],(e=>e(t))).fold((()=>Promise.resolve(t)),(n=>new Promise((o=>{((e,t,n)=>{const o=e.selection.getRng();he.setEditorTimeout(e,(()=>{e.windowManager.confirm(t,(t=>{e.selection.setRng(o),n(t)}))}))})(e,n.message,(e=>{o(e?n.preprocess(t):t)}))})))))(e,l).then((t=>{te(e,s,t)})),n.close()})(e,t);return((e,t,n)=>{const o=e.anchor.text.map((()=>({name:"text",type:"input",label:"Text to display"}))).toArray(),r=e.flags.titleEnabled?[{name:"title",type:"input",label:"Title"}]:[],l=((e,t)=>{const n=e.anchor,o=n.url.getOr("");return{url:{value:o,meta:{original:{value:o}}},text:n.text.getOr(""),title:n.title.getOr(""),anchor:o,link:o,rel:n.rel.getOr(""),target:n.target.or(t).getOr(""),linkClass:n.linkClass.getOr("")}})(e,m.from(O(n))),s=e.catalogs,a=me(l,s);return{title:"Insert/Edit Link",size:"normal",body:{type:"panel",items:f([[{name:"url",type:"urlinput",filetype:"file",label:"URL",picker_text:"Browse links"}],o,r,x([s.anchor.map(ue("anchor","Anchors")),s.rels.map(ue("rel","Rel")),s.targets.map(ue("target","Open link in...")),s.link.map(ue("link","Link list")),s.classes.map(ue("linkClass","Class"))])])},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:l,onChange:(e,{name:t})=>{a.onChange(e.getData,{name:t}).each((t=>{e.setData(t)}))},onSubmit:t}})(t,n,e)})).then((t=>{e.windowManager.open(t)}))};var Se=tinymce.util.Tools.resolve("tinymce.util.VK");const Ne=(e,t)=>{if(t){const n=V(t);if(/^#/.test(n)){const t=e.dom.select(n);t.length&&e.selection.scrollIntoView(t[0],!0)}else(e=>{const t=document.createElement("a");t.target="_blank",t.href=e,t.rel="noreferrer noopener";const n=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window});document.dispatchEvent(n),((e,t)=>{document.body.appendChild(e),e.dispatchEvent(t),document.body.removeChild(e)})(t,n)})(t.href)}},Ae=(e,t)=>{const n=W(e.dom.getParents(t));return y(1===n.length,n[0])},Te=e=>e.selection.isCollapsed()||(e=>{const t=e.selection.getRng(),n=t.startContainer;return U(n)&&t.startContainer===t.endContainer&&1===e.dom.select("img",n).length})(e)?Ae(e,e.selection.getStart()):(e=>{const t=J(e.selection.getRng());return y(t.length>0,t[0]).or(Ae(e,e.selection.getNode()))})(e),Ee=e=>()=>{e.execCommand("mceLink",!1,{dialog:!0})},Le=(e,t)=>(e.on("NodeChange",t),()=>e.off("NodeChange",t)),Re=e=>t=>{const n=()=>{t.setActive(!e.mode.isReadOnly()&&G(e,e.selection.getNode())),t.setEnabled(e.selection.isEditable())};return n(),Le(e,n)},Pe=e=>t=>{const n=()=>{t.setEnabled(e.selection.isEditable())};return n(),Le(e,n)},Me=e=>t=>{const n=e.dom.getParents(e.selection.getStart()),o=n=>{t.setEnabled((t=>{return Q(t)||(n=e.selection.getRng(),J(n).length>0);var n})(n)&&e.selection.isEditable())};return o(n),Le(e,(e=>o(e.parents)))},De=e=>{const t=(e=>{const t=(()=>{const e=(e=>{const t=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})(m.none()),n=()=>t.get().each(e);return{clear:()=>{n(),t.set(m.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{n(),t.set(m.some(e))}}})(g);return{...e,on:t=>e.get().each(t)}})(),n=()=>t.get().or(Te(e));return e.on("contextmenu",(n=>{Ae(e,n.target).each(t.set)})),e.on("SelectionChange",(()=>{t.isSet()||Te(e).each(t.set)})),e.on("click",(n=>{t.clear();const o=W(e.dom.getParents(n.target));1===o.length&&Se.metaKeyPressed(n)&&(n.preventDefault(),Ne(e,o[0]))})),e.on("keydown",(o=>{t.clear(),!o.isDefaultPrevented()&&13===o.keyCode&&(e=>!0===e.altKey&&!1===e.shiftKey&&!1===e.ctrlKey&&!1===e.metaKey)(o)&&n().each((t=>{o.preventDefault(),Ne(e,t)}))})),{gotoSelectedLink:()=>n().each((t=>Ne(e,t)))}})(e);((e,t)=>{e.ui.registry.addToggleButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Meta+K",onAction:Ee(e),onSetup:Re(e)}),e.ui.registry.addButton("openlink",{icon:"new-tab",tooltip:"Open link",onAction:t.gotoSelectedLink,onSetup:Me(e)}),e.ui.registry.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onAction:()=>ne(e),onSetup:Me(e)})})(e,t),((e,t)=>{e.ui.registry.addMenuItem("openlink",{text:"Open link",icon:"new-tab",onAction:t.gotoSelectedLink,onSetup:Me(e)}),e.ui.registry.addMenuItem("link",{icon:"link",text:"Link...",shortcut:"Meta+K",onAction:Ee(e),onSetup:Pe(e)}),e.ui.registry.addMenuItem("unlink",{icon:"unlink",text:"Remove link",onAction:()=>ne(e),onSetup:Me(e)})})(e,t),(e=>{e.ui.registry.addContextMenu("link",{update:t=>e.dom.isEditable(t)?Q(e.dom.getParents(t,"a"))?"link unlink openlink":"link":""})})(e),((e,t)=>{const n=t=>{const n=e.selection.getNode();return t.setEnabled(G(e,n)),g};e.ui.registry.addContextForm("quicklink",{launch:{type:"contextformtogglebutton",icon:"link",tooltip:"Link",onSetup:Re(e)},label:"Link",predicate:t=>w(e)&&G(e,t),initValue:()=>z(e).fold((()=>""),V),commands:[{type:"contextformtogglebutton",icon:"link",tooltip:"Link",primary:!0,onSetup:t=>{const n=e.selection.getNode();return t.setActive(G(e,n)),Re(e)(t)},onAction:t=>{const n=t.getValue(),o=(t=>{const n=z(e),o=X(e);if(n.isNone()&&o){const o=H(e.selection,n);return y(0===o.length,t)}return m.none()})(n);te(e,{href:n,attach:g},{href:n,text:o,title:m.none(),rel:m.none(),target:m.from(O(e)),class:m.none()}),(e=>{e.selection.collapse(!1)})(e),t.hide()}},{type:"contextformbutton",icon:"unlink",tooltip:"Remove link",onSetup:n,onAction:t=>{ne(e),t.hide()}},{type:"contextformbutton",icon:"new-tab",tooltip:"Open link",onSetup:n,onAction:e=>{t.gotoSelectedLink(),e.hide()}}]})})(e,t)};e.add("link",(e=>{(e=>{const t=e.options.register;t("link_assume_external_targets",{processor:e=>{const t=o(e)||a(e);return t?!0===e?{value:1,valid:t}:"http"===e||"https"===e?{value:e,valid:t}:{value:0,valid:t}:{valid:!1,message:"Must be a string or a boolean."}},default:!1}),t("link_context_toolbar",{processor:"boolean",default:!1}),t("link_list",{processor:e=>o(e)||c(e)||u(e,r)}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"}),t("link_target_list",{processor:e=>a(e)||u(e,r),default:!0}),t("link_rel_list",{processor:"object[]",default:[]}),t("link_class_list",{processor:"object[]",default:[]}),t("link_title",{processor:"boolean",default:!0}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("link_quicklink",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceLink",((t,n)=>{!0!==(null==n?void 0:n.dialog)&&R(e)?e.dispatch("contexttoolbar-show",{toolbarKey:"quicklink"}):Oe(e)}))})(e),De(e),(e=>{e.addShortcut("Meta+K","",(()=>{e.execCommand("mceLink")}))})(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/lists/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/lists/plugin.min.js new file mode 100644 index 0000000..f907976 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/lists/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var n,o,r,s})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),s=t("array"),i=n("boolean"),l=e=>!(e=>null==e)(e),a=n("function"),d=n("number"),c=()=>{},m=e=>()=>e,u=(e,t)=>e===t,p=e=>t=>!e(t),g=m(!1);class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return l(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const f=Array.prototype.slice,y=Array.prototype.indexOf,v=Array.prototype.push,C=(e,t)=>{return n=e,o=t,y.call(n,o)>-1;var n,o},b=(e,t)=>{for(let n=0,o=e.length;n{const n=e.length,o=new Array(n);for(let r=0;r{for(let n=0,o=e.length;n{const n=[];for(let o=0,r=e.length;o(S(e,((e,o)=>{n=t(n,e,o)})),n),A=(e,t,n)=>{for(let o=0,r=e.length;oA(e,t,g),x=(e,t)=>(e=>{const t=[];for(let n=0,o=e.length;n{const t=f.call(e,0);return t.reverse(),t},E=(e,t)=>t>=0&&tE(e,0),D=e=>E(e,e.length-1),B=(e,t)=>{const n=[],o=a(t)?e=>b(n,(n=>t(n,e))):e=>C(n,e);for(let t=0,r=e.length;te.exists((e=>n(e,t))),P=(e,t,n)=>e.isSome()&&t.isSome()?h.some(n(e.getOrDie(),t.getOrDie())):h.none(),I=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},R=(e,t)=>{const n=(t||document).createElement("div");if(n.innerHTML=e,!n.hasChildNodes()||n.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return I(n.childNodes[0])},U=(e,t)=>{const n=(t||document).createElement(e);return I(n)},$=I,_=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},H=(e,t)=>e.dom===t.dom,F=_,V="undefined"!=typeof window?window:Function("return this;")(),j=(e,t)=>((e,t)=>{let n=null!=t?t:V;for(let t=0;t{const t=j("ownerDocument.defaultView",e);return r(e)&&((e=>((e,t)=>{const n=((e,t)=>j(e,t))(e,t);if(null==n)throw new Error(e+" not available on this browser");return n})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(K(e).constructor.name))},Q=e=>e.dom.nodeName.toLowerCase(),W=e=>e.dom.nodeType,q=e=>t=>W(t)===e,Z=e=>G(e)&&z(e.dom),G=q(1),J=q(3),X=q(11),Y=e=>t=>G(t)&&Q(t)===e,ee=e=>h.from(e.dom.parentNode).map($),te=e=>N(e.dom.childNodes,$),ne=(e,t)=>{const n=e.dom.childNodes;return h.from(n[t]).map($)},oe=e=>ne(e,0),re=e=>ne(e,e.dom.childNodes.length-1),se=e=>$(e.dom.host),ie=e=>{const t=J(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return(e=>{const t=(e=>$(e.dom.getRootNode()))(e);return X(n=t)&&l(n.dom.host)?h.some(t):h.none();var n})($(t)).fold((()=>n.body.contains(t)),(o=ie,r=se,e=>o(r(e))));var o,r};var le=(e,t,n,o,r)=>e(n,o)?h.some(n):a(r)&&r(n)?h.none():t(n,o,r);const ae=(e,t,n)=>{let o=e.dom;const r=a(n)?n:g;for(;o.parentNode;){o=o.parentNode;const e=$(o);if(t(e))return h.some(e);if(r(e))break}return h.none()},de=(e,t,n)=>le(((e,t)=>t(e)),ae,e,t,n),ce=(e,t,n)=>ae(e,(e=>_(e,t)),n),me=(e,t)=>{ee(e).each((n=>{n.dom.insertBefore(t.dom,e.dom)}))},ue=(e,t)=>{e.dom.appendChild(t.dom)},pe=(e,t)=>{S(t,(t=>{ue(e,t)}))},ge=e=>{e.dom.textContent="",S(te(e),(e=>{he(e)}))},he=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)};var fe=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),ye=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),ve=tinymce.util.Tools.resolve("tinymce.util.VK");const Ce=e=>N(e,$),be=Object.keys,Ne=(e,t)=>{const n=be(e);for(let o=0,r=n.length;o{const n=e.dom;Ne(t,((e,t)=>{((e,t,n)=>{if(!(o(n)||i(n)||d(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(n,t,e)}))},Le=e=>O(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),Oe=e=>((e,t)=>$(e.dom.cloneNode(!0)))(e),Ae=(e,t)=>{const n=((e,t)=>{const n=U(t),o=Le(e);return Se(n,o),n})(e,t);var o,r;r=n,(e=>h.from(e.dom.nextSibling).map($))(o=e).fold((()=>{ee(o).each((e=>{ue(e,r)}))}),(e=>{me(e,r)}));const s=te(e);return pe(n,s),he(e),n};var Te=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),xe=tinymce.util.Tools.resolve("tinymce.util.Tools");const ke=e=>t=>l(t)&&t.nodeName.toLowerCase()===e,Ee=e=>t=>l(t)&&e.test(t.nodeName),we=e=>l(e)&&3===e.nodeType,De=e=>l(e)&&1===e.nodeType,Be=Ee(/^(OL|UL|DL)$/),Me=Ee(/^(OL|UL)$/),Pe=ke("ol"),Ie=Ee(/^(LI|DT|DD)$/),Re=Ee(/^(DT|DD)$/),Ue=Ee(/^(TH|TD)$/),$e=ke("br"),_e=(e,t)=>l(t)&&t.nodeName in e.schema.getTextBlockElements(),He=(e,t)=>l(e)&&e.nodeName in t,Fe=(e,t)=>l(t)&&t.nodeName in e.schema.getVoidElements(),Ve=(e,t,n)=>{const o=e.isEmpty(t);return!(n&&e.select("span[data-mce-type=bookmark]",t).length>0)&&o},je=(e,t)=>e.isChildOf(t,e.getRoot()),Ke=e=>t=>t.options.get(e),ze=Ke("lists_indent_on_tab"),Qe=Ke("forced_root_block"),We=Ke("forced_root_block_attrs"),qe=(e,t,n={})=>{const o=e.dom,r=e.schema.getBlockElements(),s=o.createFragment(),i=Qe(e),l=We(e);let a,d,c=!1;for(d=o.create(i,{...l,...n.style?{style:n.style}:{}}),He(t.firstChild,r)||s.appendChild(d);a=t.firstChild;){const e=a.nodeName;c||"SPAN"===e&&"bookmark"===a.getAttribute("data-mce-type")||(c=!0),He(a,r)?(s.appendChild(a),d=null):(d||(d=o.create(i,l),s.appendChild(d)),d.appendChild(a))}return!c&&d&&d.appendChild(o.create("br",{"data-mce-bogus":"1"})),s},Ze=Te.DOM,Ge=Y("dd"),Je=Y("dt"),Xe=(e,t)=>{var n;Ge(t)?Ae(t,"dt"):Je(t)&&(n=t,h.from(n.dom.parentElement).map($)).each((n=>((e,t,n)=>{const o=Ze.select('span[data-mce-type="bookmark"]',t),r=qe(e,n),s=Ze.createRng();s.setStartAfter(n),s.setEndAfter(t);const i=s.extractContents();for(let t=i.firstChild;t;t=t.firstChild)if("LI"===t.nodeName&&e.dom.isEmpty(t)){Ze.remove(t);break}e.dom.isEmpty(i)||Ze.insertAfter(i,t),Ze.insertAfter(r,t);const l=n.parentElement;l&&Ve(e.dom,l)&&(e=>{const t=e.parentNode;t&&xe.each(o,(e=>{t.insertBefore(e,n.parentNode)})),Ze.remove(e)})(l),Ze.remove(n),Ve(e.dom,t)&&Ze.remove(t)})(e,n.dom,t.dom)))},Ye=e=>{Je(e)&&Ae(e,"dd")},et=(e,t)=>{if(we(e))return{container:e,offset:t};const n=fe.getNode(e,t);return we(n)?{container:n,offset:t>=e.childNodes.length?n.data.length:0}:n.previousSibling&&we(n.previousSibling)?{container:n.previousSibling,offset:n.previousSibling.data.length}:n.nextSibling&&we(n.nextSibling)?{container:n.nextSibling,offset:0}:{container:e,offset:t}},tt=e=>{const t=e.cloneRange(),n=et(e.startContainer,e.startOffset);t.setStart(n.container,n.offset);const o=et(e.endContainer,e.endOffset);return t.setEnd(o.container,o.offset),t},nt=["OL","UL","DL"],ot=nt.join(","),rt=(e,t)=>{const n=t||e.selection.getStart(!0);return e.dom.getParent(n,ot,lt(e,n))},st=e=>{const t=e.selection.getSelectedBlocks();return L(((e,t)=>{const n=xe.map(t,(t=>e.dom.getParent(t,"li,dd,dt",lt(e,t))||t));return B(n)})(e,t),Ie)},it=(e,t)=>{const n=e.dom.getParents(t,"TD,TH");return n.length>0?n[0]:e.getBody()},lt=(e,t)=>{const n=e.dom.getParents(t,e.dom.isBlock),o=T(n,(t=>{return(t=>t.nodeName.toLowerCase()!==Qe(e))(t)&&(n=e.schema,!Be(o=t)&&!Ie(o)&&b(nt,(e=>n.isValidChild(o.nodeName,e))));var n,o}));return o.getOr(e.getBody())},at=(e,t)=>{const n=e.dom.getParents(t,"ol,ul",lt(e,t));return D(n)},dt=(e,t)=>{const n=N(t,(t=>at(e,t).getOr(t)));return B(n)},ct=e=>/\btox\-/.test(e.className),mt=(e,t)=>A(e,Be,Ue).exists((e=>e.nodeName===t&&!ct(e))),ut=(e,t)=>null!==t&&!e.dom.isEditable(t),pt=(e,t)=>{const n=e.dom.getParent(t,"ol,ul,dl");return ut(e,n)},gt=(e,t)=>{const n=e.selection.getNode();return t({parents:e.dom.getParents(n),element:n}),e.on("NodeChange",t),()=>e.off("NodeChange",t)},ht=(e,t)=>{const n=(t||document).createDocumentFragment();return S(e,(e=>{n.appendChild(e.dom)})),$(n)},ft=(e,t,n)=>e.dispatch("ListMutation",{action:t,element:n}),yt=(vt=/^\s+|\s+$/g,e=>e.replace(vt,""));var vt;const Ct=(e,t,n)=>{((e,t,n)=>{if(!o(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);(e=>void 0!==e.style&&a(e.style.getPropertyValue))(e)&&e.style.setProperty(t,n)})(e.dom,t,n)},bt=e=>F(e,"OL,UL"),Nt=e=>oe(e).exists(bt),St=e=>"listAttributes"in e,Lt=e=>"isComment"in e,Ot=e=>e.depth>0,At=e=>e.isSelected,Tt=e=>{const t=te(e),n=re(e).exists(bt)?t.slice(0,-1):t;return N(n,Oe)},xt=(e,t)=>{ue(e.item,t.list)},kt=(e,t)=>{const n={list:U(t,e),item:U("li",e)};return ue(n.list,n.item),n},Et=(e,t,n)=>{const o=t.slice(0,n.depth);return D(o).each((t=>{if(St(n)){const o=((e,t,n)=>{const o=U("li",e);return Se(o,t),pe(o,n),o})(e,n.itemAttributes,n.content);((e,t)=>{ue(e.list,t),e.item=t})(t,o),((e,t)=>{Q(e.list)!==t.listType&&(e.list=Ae(e.list,t.listType)),Se(e.list,t.listAttributes)})(t,n)}else if((e=>"isFragment"in e)(n))pe(t.item,n.content);else{const e=R(`\x3c!--${n.content}--\x3e`);ue(t.list,e)}})),o},wt=(e,t)=>{let n=h.none();const o=O(t,((t,o,r)=>Lt(o)?0===r?(n=h.some(o),t):Et(e,t,o):o.depth>t.length?((e,t,n)=>{const o=((e,t,n)=>{const o=[];for(let r=0;r{for(let t=1;t{for(let t=0;t{St(t)&&(Se(e.list,t.listAttributes),Se(e.item,t.itemAttributes)),pe(e.item,t.content)}))})(o,n),r=o,P(D(t),w(r),xt),t.concat(o)})(e,t,o):Et(e,t,o)),[]);return n.each((e=>{const t=R(`\x3c!--${e.content}--\x3e`);w(o).each((e=>{((e,t)=>{oe(e).fold((()=>{ue(e,t)}),(n=>{e.dom.insertBefore(t.dom,n.dom)}))})(e.list,t)}))})),w(o).map((e=>e.list))},Dt=e=>(S(e,((t,n)=>{((e,t)=>{const n=e[t].depth,o=e=>e.depth===n&&!e.dirty,r=e=>e.depthA(e.slice(t+1),o,r)))})(e,n).fold((()=>{t.dirty&&St(t)&&(e=>{e.listAttributes=((e,t)=>{const n={};var o;return((e,t,n,o)=>{Ne(e,((e,r)=>{(t(e,r)?n:o)(e,r)}))})(e,t,(o=n,(e,t)=>{o[t]=e}),c),n})(e.listAttributes,((e,t)=>"start"!==t))})(t)}),(e=>{return o=e,void(St(n=t)&&St(o)&&(n.listType=o.listType,n.listAttributes={...o.listAttributes}));var n,o}))})),e),Bt=(e,t,n,o)=>{var r,s;if(8===W(s=o)||"#comment"===Q(s))return[{depth:e+1,content:null!==(r=o.dom.nodeValue)&&void 0!==r?r:"",dirty:!1,isSelected:!1,isComment:!0}];t.each((e=>{H(e.start,o)&&n.set(!0)}));const i=((e,t,n)=>ee(e).filter(G).map((o=>({depth:t,dirty:!1,isSelected:n,content:Tt(e),itemAttributes:Le(e),listAttributes:Le(o),listType:Q(o),isInPreviousLi:!1}))))(o,e,n.get());t.each((e=>{H(e.end,o)&&n.set(!1)}));const l=re(o).filter(bt).map((o=>Pt(e,t,n,o))).getOr([]);return i.toArray().concat(l)},Mt=(e,t,n,o)=>oe(o).filter(bt).fold((()=>Bt(e,t,n,o)),(r=>{const s=O(te(o),((o,s,i)=>{if(0===i)return o;if(F(s,"LI"))return o.concat(Bt(e,t,n,s));{const t={isFragment:!0,depth:e,content:[s],isSelected:!1,dirty:!1,parentListType:Q(r)};return o.concat(t)}}),[]);return Pt(e,t,n,r).concat(s)})),Pt=(e,t,n,o)=>x(te(o),(o=>(bt(o)?Pt:Mt)(e+1,t,n,o))),It=(e,t,n)=>{const o=((e,t)=>{const n=(e=>{let t=!1;return{get:()=>t,set:e=>{t=e}}})();return N(e,(e=>({sourceList:e,entries:Pt(0,t,n,e)})))})(t,(e=>{const t=N(st(e),$);return P(T(t,p(Nt)),T(k(t),p(Nt)),((e,t)=>({start:e,end:t})))})(e));S(o,(t=>{((e,t)=>{S(L(e,At),(e=>((e,t)=>{switch(e){case"Indent":t.depth++;break;case"Outdent":t.depth--;break;case"Flatten":t.depth=0}t.dirty=!0})(t,e)))})(t.entries,n);const o=((e,t)=>x(((e,t)=>{if(0===e.length)return[];{let n=t(e[0]);const o=[];let r=[];for(let s=0,i=e.length;sw(t).exists(Ot)?((e,t)=>{const n=Dt(t);return wt(e.contentDocument,n).toArray()})(e,t):((e,t)=>{const n=Dt(t);return N(n,(t=>{const n=Lt(t)?ht([R(`\x3c!--${t.content}--\x3e`)]):ht(t.content),o=St(t)?t.itemAttributes:{};return $(qe(e,n.dom,o))}))})(e,t))))(e,t.entries);var r;S(o,(t=>{ft(e,"Indent"===n?"IndentList":"OutdentList",t.dom)})),r=t.sourceList,S(o,(e=>{me(r,e)})),he(t.sourceList)}))},Rt=(e,t)=>{const n=Ce((e=>{const t=(e=>{const t=at(e,e.selection.getStart()),n=L(e.selection.getSelectedBlocks(),Me);return t.toArray().concat(n)})(e),n=(e=>{const t=e.selection.getStart();return e.dom.getParents(t,"ol,ul",lt(e,t))})(e);return T(n,(e=>{return t=$(e),ee(t).exists((e=>Ie(e.dom)&&oe(e).exists((e=>!Be(e.dom)))&&re(e).exists((e=>!Be(e.dom)))));var t})).fold((()=>dt(e,t)),(e=>[e]))})(e)),o=Ce((e=>L(st(e),Re))(e));let r=!1;if(n.length||o.length){const s=e.selection.getBookmark();It(e,n,t),((e,t,n)=>{S(n,"Indent"===t?Ye:t=>Xe(e,t))})(e,t,o),e.selection.moveToBookmark(s),e.selection.setRng(tt(e.selection.getRng())),e.nodeChanged(),r=!0}return r},Ut=(e,t)=>!(e=>{const t=rt(e);return ut(e,t)})(e)&&Rt(e,t),$t=e=>Ut(e,"Indent"),_t=e=>Ut(e,"Outdent"),Ht=e=>Ut(e,"Flatten"),Ft=e=>"\ufeff"===e;var Vt=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const jt=Te.DOM,Kt=e=>{const t={},n=n=>{let o=e[n?"startContainer":"endContainer"],r=e[n?"startOffset":"endOffset"];if(De(o)){const e=jt.create("span",{"data-mce-type":"bookmark"});o.hasChildNodes()?(r=Math.min(r,o.childNodes.length-1),n?o.insertBefore(e,o.childNodes[r]):jt.insertAfter(e,o.childNodes[r])):o.appendChild(e),o=e,r=0}t[n?"startContainer":"endContainer"]=o,t[n?"startOffset":"endOffset"]=r};return n(!0),e.collapsed||n(),t},zt=e=>{const t=t=>{let n=e[t?"startContainer":"endContainer"],o=e[t?"startOffset":"endOffset"];if(n){if(De(n)&&n.parentNode){const e=n;o=(e=>{var t;let n=null===(t=e.parentNode)||void 0===t?void 0:t.firstChild,o=0;for(;n;){if(n===e)return o;De(n)&&"bookmark"===n.getAttribute("data-mce-type")||o++,n=n.nextSibling}return-1})(n),n=n.parentNode,jt.remove(e),!n.hasChildNodes()&&jt.isBlock(n)&&n.appendChild(jt.create("br"))}e[t?"startContainer":"endContainer"]=n,e[t?"startOffset":"endOffset"]=o}};t(!0),t();const n=jt.createRng();return n.setStart(e.startContainer,e.startOffset),e.endContainer&&n.setEnd(e.endContainer,e.endOffset),tt(n)},Qt=e=>{switch(e){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},Wt=(e,t)=>{xe.each(t,((t,n)=>{e.setAttribute(n,t)}))},qt=(e,t,n)=>{((e,t,n)=>{const o=n["list-style-type"]?n["list-style-type"]:null;e.setStyle(t,"list-style-type",o)})(e,t,n),((e,t,n)=>{Wt(t,n["list-attributes"]),xe.each(e.select("li",t),(e=>{Wt(e,n["list-item-attributes"])}))})(e,t,n)},Zt=(e,t)=>l(t)&&!He(t,e.schema.getBlockElements()),Gt=(e,t,n,o)=>{let r=t[n?"startContainer":"endContainer"];const s=t[n?"startOffset":"endOffset"];De(r)&&(r=r.childNodes[Math.min(s,r.childNodes.length-1)]||r),!n&&$e(r.nextSibling)&&(r=r.nextSibling);const i=(t,n)=>{var r;const s=new ye(t,(t=>{for(;!e.dom.isBlock(t)&&t.parentNode&&o!==t;)t=t.parentNode;return t})(t)),i=n?"next":"prev";let l;for(;l=s[i]();)if(!Fe(e,l)&&!Ft(l.textContent)&&0!==(null===(r=l.textContent)||void 0===r?void 0:r.length))return h.some(l);return h.none()};if(n&&we(r))if(Ft(r.textContent))r=i(r,!1).getOr(r);else for(null!==r.parentNode&&Zt(e,r.parentNode)&&(r=r.parentNode);null!==r.previousSibling&&(Zt(e,r.previousSibling)||we(r.previousSibling));)r=r.previousSibling;if(!n&&we(r))if(Ft(r.textContent))r=i(r,!0).getOr(r);else for(null!==r.parentNode&&Zt(e,r.parentNode)&&(r=r.parentNode);null!==r.nextSibling&&(Zt(e,r.nextSibling)||we(r.nextSibling));)r=r.nextSibling;for(;r.parentNode!==o;){const t=r.parentNode;if(_e(e,r))return r;if(/^(TD|TH)$/.test(t.nodeName))return r;r=t}return r},Jt=(e,t,n)=>{const o=e.selection.getRng();let r="LI";const s=lt(e,((e,t)=>{const n=e.selection.getStart(!0),o=Gt(e,t,!0,e.getBody());return r=$(o),s=$(t.commonAncestorContainer),i=r,l=function(e,...t){return(...n)=>{const o=t.concat(n);return e.apply(null,o)}}(H,s),ae(i,l,void 0).isSome()?t.commonAncestorContainer:n;var r,s,i,l})(e,o)),i=e.dom;if("false"===i.getContentEditable(e.selection.getNode()))return;"DL"===(t=t.toUpperCase())&&(r="DT");const l=Kt(o),a=L(((e,t,n)=>{const o=[],r=e.dom,s=Gt(e,t,!0,n),i=Gt(e,t,!1,n);let l;const a=[];for(let e=s;e&&(a.push(e),e!==i);e=e.nextSibling);return xe.each(a,(t=>{var s;if(_e(e,t))return o.push(t),void(l=null);if(r.isBlock(t)||$e(t))return $e(t)&&r.remove(t),void(l=null);const i=t.nextSibling;Vt.isBookmarkNode(t)&&(Be(i)||_e(e,i)||!i&&t.parentNode===n)?l=null:(l||(l=r.create("p"),null===(s=t.parentNode)||void 0===s||s.insertBefore(l,t),o.push(l)),l.appendChild(t))})),o})(e,o,s),e.dom.isEditable);xe.each(a,(o=>{let s;const l=o.previousSibling,a=o.parentNode;Ie(a)||(l&&Be(l)&&l.nodeName===t&&((e,t,n)=>{const o=e.getStyle(t,"list-style-type");let r=n?n["list-style-type"]:"";return r=null===r?"":r,o===r})(i,l,n)?(s=l,o=i.rename(o,r),l.appendChild(o)):(s=i.create(t),a.insertBefore(s,o),s.appendChild(o),o=i.rename(o,r)),((e,t,n)=>{xe.each(["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"],(n=>e.setStyle(t,n,"")))})(i,o),qt(i,s,n),Yt(e.dom,s))})),e.selection.setRng(zt(l))},Xt=(e,t,n)=>{return((e,t)=>Be(e)&&e.nodeName===(null==t?void 0:t.nodeName))(t,n)&&((e,t,n)=>e.getStyle(t,"list-style-type",!0)===e.getStyle(n,"list-style-type",!0))(e,t,n)&&(o=n,t.className===o.className);var o},Yt=(e,t)=>{let n,o=t.nextSibling;if(Xt(e,t,o)){const r=o;for(;n=r.firstChild;)t.appendChild(n);e.remove(r)}if(o=t.previousSibling,Xt(e,t,o)){const r=o;for(;n=r.lastChild;)t.insertBefore(n,t.firstChild);e.remove(r)}},en=(e,t,n,o)=>{if(t.nodeName!==n){const r=e.dom.rename(t,n);qt(e.dom,r,o),ft(e,Qt(n),r)}else qt(e.dom,t,o),ft(e,Qt(n),t)},tn=(e,t,n,o)=>{if(t.classList.forEach(((e,n,o)=>{e.startsWith("tox-")&&(o.remove(e),0===o.length&&t.removeAttribute("class"))})),t.nodeName!==n){const r=e.dom.rename(t,n);qt(e.dom,r,o),ft(e,Qt(n),r)}else qt(e.dom,t,o),ft(e,Qt(n),t)},nn=e=>"list-style-type"in e,on=(e,t,n)=>{const o=rt(e);if(pt(e,o))return;const s=(e=>{const t=rt(e),n=e.selection.getSelectedBlocks();return((e,t)=>l(e)&&1===t.length&&t[0]===e)(t,n)?(e=>L(e.querySelectorAll(ot),Be))(t):L(n,(e=>Be(e)&&t!==e))})(e),i=r(n)?n:{};s.length>0?((e,t,n,o,r)=>{const s=Be(t);if(!s||t.nodeName!==o||nn(r)||ct(t)){Jt(e,o,r);const i=Kt(e.selection.getRng()),l=s?[t,...n]:n,a=s&&ct(t)?tn:en;xe.each(l,(t=>{a(e,t,o,r)})),e.selection.setRng(zt(i))}else Ht(e)})(e,o,s,t,i):((e,t,n,o)=>{if(t!==e.getBody())if(t)if(t.nodeName!==n||nn(o)||ct(t)){const r=Kt(e.selection.getRng());ct(t)&&t.classList.forEach(((e,n,o)=>{e.startsWith("tox-")&&(o.remove(e),0===o.length&&t.removeAttribute("class"))})),qt(e.dom,t,o);const s=e.dom.rename(t,n);Yt(e.dom,s),e.selection.setRng(zt(r)),Jt(e,n,o),ft(e,Qt(n),s)}else Ht(e);else Jt(e,n,o),ft(e,Qt(n),t)})(e,o,t,i)},rn=Te.DOM,sn=(e,t)=>{const n=xe.grep(e.select("ol,ul",t));xe.each(n,(t=>{((e,t)=>{const n=t.parentElement;if(n&&"LI"===n.nodeName&&n.firstChild===t){const o=n.previousSibling;o&&"LI"===o.nodeName?(o.appendChild(t),Ve(e,n)&&rn.remove(n)):rn.setStyle(n,"listStyleType","none")}if(Be(n)){const e=n.previousSibling;e&&"LI"===e.nodeName&&e.appendChild(t)}})(e,t)}))},ln=(e,t,n,o)=>{let r=t.startContainer;const s=t.startOffset;if(we(r)&&(n?s0))return r;const i=e.schema.getNonEmptyElements();De(r)&&(r=fe.getNode(r,s));const l=new ye(r,o);n&&((e,t)=>!!$e(t)&&e.isBlock(t.nextSibling)&&!$e(t.previousSibling))(e.dom,r)&&l.next();const a=n?l.next.bind(l):l.prev2.bind(l);for(;r=a();){if("LI"===r.nodeName&&!r.hasChildNodes())return r;if(i[r.nodeName])return r;if(we(r)&&r.data.length>0)return r}return null},an=(e,t)=>{const n=t.childNodes;return 1===n.length&&!Be(n[0])&&e.isBlock(n[0])},dn=e=>h.from(e).map($).filter(Z).exists((e=>((e,t=!1)=>{return ie(e)?e.dom.isContentEditable:(n=e,le(((e,t)=>_(e,t)),ce,n,"[contenteditable]",void 0)).fold(m(t),(e=>"true"===(e=>e.dom.contentEditable)(e)));var n})(e)&&!C(["details"],Q(e)))),cn=(e,t,n)=>{let o;const r=an(e,n)?n.firstChild:n;if(((e,t)=>{an(e,t)&&dn(t.firstChild)&&e.remove(t.firstChild,!0)})(e,t),!Ve(e,t,!0))for(;o=t.firstChild;)r.appendChild(o)},mn=(e,t,n)=>{let o;const r=t.parentNode;if(!je(e,t)||!je(e,n))return;Be(n.lastChild)&&(o=n.lastChild),r===n.lastChild&&$e(r.previousSibling)&&e.remove(r.previousSibling);const s=n.lastChild;s&&$e(s)&&t.hasChildNodes()&&e.remove(s),Ve(e,n,!0)&&ge($(n)),cn(e,t,n),o&&n.appendChild(o);const i=((e,t)=>{const n=e.dom,o=t.dom;return n!==o&&n.contains(o)})($(n),$(t))?e.getParents(t,Be,n):[];e.remove(t),S(i,(t=>{Ve(e,t)&&t!==e.getRoot()&&e.remove(t)}))},un=(e,t)=>{const n=e.dom,o=e.selection,r=o.getStart(),s=it(e,r),i=n.getParent(o.getStart(),"LI",s);if(i){const r=i.parentElement;if(r===e.getBody()&&Ve(n,r))return!0;const l=tt(o.getRng()),a=n.getParent(ln(e,l,t,s),"LI",s),d=a&&(t?n.isChildOf(i,a):n.isChildOf(a,i));if(a&&a!==i&&!d)return e.undoManager.transact((()=>{var n,o;t?((e,t,n,o)=>{const r=e.dom;if(r.isEmpty(o))((e,t,n)=>{ge($(n)),mn(e.dom,t,n),e.selection.setCursorLocation(n,0)})(e,n,o);else{const s=Kt(t);mn(r,n,o),e.selection.setRng(zt(s))}})(e,l,a,i):(null===(o=(n=i).parentNode)||void 0===o?void 0:o.firstChild)===n?_t(e):((e,t,n,o)=>{const r=Kt(t);mn(e.dom,n,o);const s=zt(r);e.selection.setRng(s)})(e,l,i,a)})),!0;if(d&&!t&&a!==i)return e.undoManager.transact((()=>{if(l.commonAncestorContainer.parentElement){const t=Kt(l),o=l.commonAncestorContainer.parentElement;cn(n,l.commonAncestorContainer.parentElement,a),o.remove();const r=zt(t);e.selection.setRng(r)}})),!0;if(!a&&!t&&0===l.startOffset&&0===l.endOffset)return e.undoManager.transact((()=>{Ht(e)})),!0}return!1},pn=e=>{const t=e.selection.getStart(),n=it(e,t);return e.dom.getParent(t,"LI,DT,DD",n)||st(e).length>0},gn=(e,t)=>{const n=e.selection;return!pt(e,n.getNode())&&(n.isCollapsed()?((e,t)=>un(e,t)||((e,t)=>{const n=e.dom,o=e.selection.getStart(),r=it(e,o),s=n.getParent(o,n.isBlock,r);if(s&&n.isEmpty(s,void 0,{checkRootAsContent:!0})){const o=tt(e.selection.getRng()),i=n.getParent(ln(e,o,t,r),"LI",r);if(i){const l=e=>C(["td","th","caption"],Q(e)),a=e=>e.dom===r;return!!((e,t,n=u)=>P(e,t,n).getOr(e.isNone()&&t.isNone()))(de($(i),l,a),de($(o.startContainer),l,a),H)&&(e.undoManager.transact((()=>{const o=i.parentNode;((e,t,n)=>{const o=e.getParent(t.parentNode,e.isBlock,n);e.remove(t),o&&e.isEmpty(o)&&e.remove(o)})(n,s,r),Yt(n,o),e.selection.select(i,!0),e.selection.collapse(t)})),!0)}}return!1})(e,t))(e,t):(e=>!!pn(e)&&(e.undoManager.transact((()=>{e.execCommand("Delete"),sn(e.dom,e.getBody())})),!0))(e))},hn=e=>{const t=k(yt(e).split("")),n=N(t,((e,t)=>{const n=e.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,t)*n}));return O(n,((e,t)=>e+t),0)},fn=e=>{if(--e<0)return"";{const t=e%26,n=Math.floor(e/26);return fn(n)+String.fromCharCode("A".charCodeAt(0)+t)}},yn=e=>{const t=parseInt(e.start,10);return M(e.listStyleType,"upper-alpha")?fn(t):M(e.listStyleType,"lower-alpha")?fn(t).toLowerCase():e.start},vn=(e,t)=>()=>{const n=rt(e);return l(n)&&n.nodeName===t},Cn=e=>{e.addCommand("mceListProps",(()=>{(e=>{const t=rt(e);Pe(t)&&!pt(e,t)&&e.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:yn({start:e.dom.getAttrib(t,"start","1"),listStyleType:h.from(e.dom.getStyle(t,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{(e=>{switch((e=>/^[0-9]+$/.test(e)?2:/^[A-Z]+$/.test(e)?0:/^[a-z]+$/.test(e)?1:e.length>0?4:3)(e)){case 2:return h.some({listStyleType:h.none(),start:e});case 0:return h.some({listStyleType:h.some("upper-alpha"),start:hn(e).toString()});case 1:return h.some({listStyleType:h.some("lower-alpha"),start:hn(e).toString()});case 3:return h.some({listStyleType:h.none(),start:""});case 4:return h.none()}})(t.getData().start).each((t=>{e.execCommand("mceListUpdate",!1,{attrs:{start:"1"===t.start?"":t.start},styles:{"list-style-type":t.listStyleType.getOr("")}})})),t.close()}})})(e)}))};var bn=tinymce.util.Tools.resolve("tinymce.html.Node");const Nn=e=>3===e.type,Sn=e=>0===e.length,Ln=e=>{const t=(t,n)=>{const o=bn.create("li");S(t,(e=>o.append(e))),n?e.insert(o,n,!0):e.append(o)},n=O(e.children(),((e,n)=>Nn(n)?[...e,n]:Sn(e)||Nn(n)?e:(t(e,n),[])),[]);Sn(n)||t(n)},On=(e,t)=>n=>(n.setEnabled(e.selection.isEditable()),gt(e,(o=>{n.setActive(mt(o.parents,t)),n.setEnabled(!pt(e,o.element)&&e.selection.isEditable())}))),An=(e,t)=>n=>gt(e,(o=>n.setEnabled(mt(o.parents,t)&&!pt(e,o.element))));e.add("lists",(e=>((e=>{(0,e.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(e),(e=>{e.on("PreInit",(()=>{const{parser:t}=e;t.addNodeFilter("ul,ol",(e=>S(e,Ln)))}))})(e),e.hasPlugin("rtc",!0)?Cn(e):((e=>{ze(e)&&(e=>{e.on("keydown",(t=>{t.keyCode!==ve.TAB||ve.metaKeyPressed(t)||e.undoManager.transact((()=>{(t.shiftKey?_t(e):$t(e))&&t.preventDefault()}))}))})(e),(e=>{e.on("ExecCommand",(t=>{const n=t.command.toLowerCase();"delete"!==n&&"forwarddelete"!==n||!pn(e)||sn(e.dom,e.getBody())})),e.on("keydown",(t=>{t.keyCode===ve.BACKSPACE?gn(e,!1)&&t.preventDefault():t.keyCode===ve.DELETE&&gn(e,!0)&&t.preventDefault()}))})(e)})(e),(e=>{e.on("BeforeExecCommand",(t=>{const n=t.command.toLowerCase();"indent"===n?$t(e):"outdent"===n&&_t(e)})),e.addCommand("InsertUnorderedList",((t,n)=>{on(e,"UL",n)})),e.addCommand("InsertOrderedList",((t,n)=>{on(e,"OL",n)})),e.addCommand("InsertDefinitionList",((t,n)=>{on(e,"DL",n)})),e.addCommand("RemoveList",(()=>{Ht(e)})),Cn(e),e.addCommand("mceListUpdate",((t,n)=>{r(n)&&((e,t)=>{const n=rt(e);null===n||pt(e,n)||e.undoManager.transact((()=>{r(t.styles)&&e.dom.setStyles(n,t.styles),r(t.attrs)&&Ne(t.attrs,((t,o)=>e.dom.setAttrib(n,o,t)))}))})(e,n)})),e.addQueryStateHandler("InsertUnorderedList",vn(e,"UL")),e.addQueryStateHandler("InsertOrderedList",vn(e,"OL")),e.addQueryStateHandler("InsertDefinitionList",vn(e,"DL"))})(e)),(e=>{const t=t=>()=>e.execCommand(t);e.hasPlugin("advlist")||(e.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:t("InsertOrderedList"),onSetup:On(e,"OL")}),e.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:t("InsertUnorderedList"),onSetup:On(e,"UL")}))})(e),(e=>{const t={text:"List properties...",icon:"ordered-list",onAction:()=>e.execCommand("mceListProps"),onSetup:An(e,"OL")};e.ui.registry.addMenuItem("listprops",t),e.ui.registry.addContextMenu("lists",{update:t=>{const n=rt(e,t);return Pe(n)?["listprops"]:[]}})})(e),(e=>({backspaceDelete:t=>{gn(e,t)}}))(e))))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/media/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/media/plugin.min.js new file mode 100644 index 0000000..955850d --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/media/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=o=e,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":t;var r,o,a,s})(t)===e,r=t("string"),o=t("object"),a=t("array"),s=e=>!(e=>null==e)(e);class i{constructor(e,t){this.tag=e,this.value=t}static some(e){return new i(!0,e)}static none(){return i.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?i.some(e(this.value)):i.none()}bind(e){return this.tag?e(this.value):i.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:i.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?i.some(e):i.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}i.singletonNone=new i(!1);const n=Array.prototype.push,l=(e,t)=>{for(let r=0,o=e.length;r{const t=[];for(let r=0,o=e.length;rh(e,t)?i.from(e[t]):i.none(),h=(e,t)=>u.call(e,t),p=e=>t=>t.options.get(e),g=p("audio_template_callback"),b=p("video_template_callback"),w=p("iframe_template_callback"),v=p("media_live_embeds"),f=p("media_filter_html"),y=p("media_url_resolver"),x=p("media_alt_source"),_=p("media_poster"),k=p("media_dimensions");var j=tinymce.util.Tools.resolve("tinymce.util.Tools"),O=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),A=tinymce.util.Tools.resolve("tinymce.html.DomParser");const S=O.DOM,$=e=>e.replace(/px$/,""),C=e=>{const t=e.attr("style"),r=t?S.parseStyle(t):{};return{type:"ephox-embed-iri",source:e.attr("data-ephox-embed-iri"),altsource:"",poster:"",width:d(r,"max-width").map($).getOr(""),height:d(r,"max-height").map($).getOr("")}},T=(e,t)=>{let r={};for(let o=A({validate:!1,forced_root_block:!1},t).parse(e);o;o=o.walk())if(1===o.type){const e=o.name;if(o.attr("data-ephox-embed-iri")){r=C(o);break}r.source||"param"!==e||(r.source=o.attr("movie")),"iframe"!==e&&"object"!==e&&"embed"!==e&&"video"!==e&&"audio"!==e||(r.type||(r.type=e),r=j.extend(o.attributes.map,r)),"source"===e&&(r.source?r.altsource||(r.altsource=o.attr("src")):r.source=o.attr("src")),"img"!==e||r.poster||(r.poster=o.attr("src"))}return r.source=r.source||r.src||"",r.altsource=r.altsource||"",r.poster=r.poster||"",r},z=e=>{var t;const r=null!==(t=e.toLowerCase().split(".").pop())&&void 0!==t?t:"";return d({mp3:"audio/mpeg",m4a:"audio/x-m4a",wav:"audio/wav",mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",swf:"application/x-shockwave-flash"},r).getOr("")};var D=tinymce.util.Tools.resolve("tinymce.html.Node"),F=tinymce.util.Tools.resolve("tinymce.html.Serializer");const M=(e,t={})=>A({forced_root_block:!1,validate:!1,allow_conditional_comments:!0,...t},e),N=O.DOM,P=e=>/^[0-9.]+$/.test(e)?e+"px":e,R=(e,t)=>{const r=t.attr("style"),o=r?N.parseStyle(r):{};s(e.width)&&(o["max-width"]=P(e.width)),s(e.height)&&(o["max-height"]=P(e.height)),t.attr("style",N.serializeStyle(o))},E=["source","altsource"],U=(e,t,r,o)=>{let a=0,s=0;const i=M(o);i.addNodeFilter("source",(e=>a=e.length));const n=i.parse(e);for(let e=n;e;e=e.walk())if(1===e.type){const o=e.name;if(e.attr("data-ephox-embed-iri")){R(t,e);break}switch(o){case"video":case"object":case"embed":case"img":case"iframe":void 0!==t.height&&void 0!==t.width&&(e.attr("width",t.width),e.attr("height",t.height))}if(r)switch(o){case"video":e.attr("poster",t.poster),e.attr("src",null);for(let r=a;r<2;r++)if(t[E[r]]){const o=new D("source",1);o.attr("src",t[E[r]]),o.attr("type",t[E[r]+"mime"]||null),e.append(o)}break;case"iframe":e.attr("src",t.source);break;case"object":const r=e.getAll("img").length>0;if(t.poster&&!r){e.attr("src",t.poster);const r=new D("img",1);r.attr("src",t.poster),r.attr("width",t.width),r.attr("height",t.height),e.append(r)}break;case"source":if(s<2&&(e.attr("src",t[E[s]]),e.attr("type",t[E[s]+"mime"]||null),!t[E[s]])){e.remove();continue}s++;break;case"img":t.poster||e.remove()}}return F({},o).serialize(n)},L=[{regex:/youtu\.be\/([\w\-_\?&=.]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$2?$4",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?h=$3&title=0&byline=0",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?title=0&byline=0",allowFullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0},{regex:/dai\.ly\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],I=(e,t)=>{const r=(e=>{const t=e.match(/^(https?:\/\/|www\.)(.+)$/i);return t&&t.length>1?"www."===t[1]?"https://":t[1]:"https://"})(t),o=e.regex.exec(t);let a=r+e.url;if(s(o))for(let e=0;eo[e]?o[e]:""));return a.replace(/\?$/,"")},B=e=>{const t=L.filter((t=>t.regex.test(e)));return t.length>0?j.extend({},t[0],{url:I(t[0],e)}):null},G=(e,t)=>{var r;const o=j.extend({},t);if(!o.source&&(j.extend(o,T(null!==(r=o.embed)&&void 0!==r?r:"",e.schema)),!o.source))return"";o.altsource||(o.altsource=""),o.poster||(o.poster=""),o.source=e.convertURL(o.source,"source"),o.altsource=e.convertURL(o.altsource,"source"),o.sourcemime=z(o.source),o.altsourcemime=z(o.altsource),o.poster=e.convertURL(o.poster,"poster");const a=B(o.source);if(a&&(o.source=a.url,o.type=a.type,o.allowfullscreen=a.allowFullscreen,o.width=o.width||String(a.w),o.height=o.height||String(a.h)),o.embed)return U(o.embed,o,!0,e.schema);{const t=g(e),r=b(e),a=w(e);return o.width=o.width||"300",o.height=o.height||"150",j.each(o,((t,r)=>{o[r]=e.dom.encode(""+t)})),"iframe"===o.type?((e,t)=>{if(t)return t(e);{const t=e.allowfullscreen?' allowFullscreen="1"':"";return'"}})(o,a):"application/x-shockwave-flash"===o.sourcemime?(e=>{let t='';return e.poster&&(t+=''),t+="",t})(o):-1!==o.sourcemime.indexOf("audio")?((e,t)=>t?t(e):'")(o,t):((e,t)=>t?t(e):'")(o,r)}},W=e=>e.hasAttribute("data-mce-object")||e.hasAttribute("data-ephox-embed-iri"),q={},H=e=>t=>G(e,t),J=(e,t)=>{const r=y(e);return r?((e,t,r)=>new Promise(((o,a)=>{const s=r=>(r.html&&(q[e.source]=r),o({url:e.source,html:r.html?r.html:t(e)}));q[e.source]?s(q[e.source]):r({url:e.source}).then(s).catch(a)})))(t,H(e),r):((e,t)=>Promise.resolve({html:t(e),url:e.source}))(t,H(e))},K=(e,t)=>{const r={};return d(e,"dimensions").each((e=>{l(["width","height"],(o=>{d(t,o).orThunk((()=>d(e,o))).each((e=>r[o]=e))}))})),r},Q=(e,t)=>{const r=t&&"dimensions"!==t?((e,t)=>d(t,e).bind((e=>d(e,"meta"))))(t,e).getOr({}):{},a=((e,t,r)=>a=>{const s=()=>d(e,a),n=()=>d(t,a),l=e=>d(e,"value").bind((e=>e.length>0?i.some(e):i.none()));return{[a]:(a===r?s().bind((e=>o(e)?l(e).orThunk(n):n().orThunk((()=>i.from(e))))):n().orThunk((()=>s().bind((e=>o(e)?l(e):i.from(e)))))).getOr("")}})(e,r,t);return{...a("source"),...a("altsource"),...a("poster"),...a("embed"),...K(e,r)}},V=e=>{const t={...e,source:{value:d(e,"source").getOr("")},altsource:{value:d(e,"altsource").getOr("")},poster:{value:d(e,"poster").getOr("")}};return l(["width","height"],(r=>{d(e,r).each((e=>{const o=t.dimensions||{};o[r]=e,t.dimensions=o}))})),t},X=e=>t=>{const r=t&&t.msg?"Media embed handler error: "+t.msg:"Media embed handler threw unknown error.";e.notificationManager.open({type:"error",text:r})},Y=(e,t)=>o=>{if(r(o.url)&&o.url.trim().length>0){const r=o.html,a={...T(r,t.schema),source:o.url,embed:r};e.setData(V(a))}},Z=(e,t)=>{const r=e.dom.select("*[data-mce-object]");e.insertContent(t),((e,t)=>{const r=e.dom.select("*[data-mce-object]");for(let e=0;e=0;o--)t[e]===r[o]&&r.splice(o,1);e.selection.select(r[0])})(e,r),e.nodeChanged()},ee=(e,t)=>s(t)&&"ephox-embed-iri"===t&&s(B(e)),te=(e,t)=>((e,t)=>e.width!==t.width||e.height!==t.height)(e,t)&&ee(t.source,e.type),re=e=>{const t=(e=>{const t=e.selection.getNode(),r=W(t)?e.serializer.serialize(t,{selection:!0}):"",o=T(r,e.schema),a=(()=>{if(ee(o.source,o.type)){const r=e.dom.getRect(t);return{width:r.w.toString().replace(/px$/,""),height:r.h.toString().replace(/px$/,"")}}return{}})();return{embed:r,...o,...a}})(e),r=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})(t),o=V(t),a=k(e)?[{type:"sizeinput",name:"dimensions",label:"Constrain proportions",constrain:!0}]:[],s={title:"General",name:"general",items:c([[{name:"source",type:"urlinput",filetype:"media",label:"Source",picker_text:"Browse files"}],a])},i=[];x(e)&&i.push({name:"altsource",type:"urlinput",filetype:"media",label:"Alternative source URL"}),_(e)&&i.push({name:"poster",type:"urlinput",filetype:"image",label:"Media poster (Image URL)"});const n={title:"Advanced",name:"advanced",items:i},l=[s,{title:"Embed",items:[{type:"textarea",name:"embed",label:"Paste your embed code below:"}]}];i.length>0&&l.push(n);const m={type:"tabpanel",tabs:l},u=e.windowManager.open({title:"Insert/Edit Media",size:"normal",body:m,buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{const o=Q(t.getData());((e,t,r)=>{var o,a;t.embed=te(e,t)&&k(r)?G(r,{...t,embed:""}):U(null!==(o=t.embed)&&void 0!==o?o:"",t,!1,r.schema),t.embed&&(e.source===t.source||(a=t.source,h(q,a)))?Z(r,t.embed):J(r,t).then((e=>{Z(r,e.html)})).catch(X(r))})(r.get(),o,e),t.close()},onChange:(t,o)=>{switch(o.name){case"source":((t,r)=>{const o=Q(r.getData(),"source");t.source!==o.source&&(Y(u,e)({url:o.source,html:""}),J(e,o).then(Y(u,e)).catch(X(e)))})(r.get(),t);break;case"embed":(t=>{var r;const o=Q(t.getData()),a=T(null!==(r=o.embed)&&void 0!==r?r:"",e.schema);t.setData(V(a))})(t);break;case"dimensions":case"altsource":case"poster":((t,r,o)=>{const a=Q(t.getData(),r),s=te(o,a)&&k(e)?{...a,embed:""}:a,i=G(e,s);t.setData(V({...s,embed:i}))})(t,o.name,r.get())}r.set(Q(t.getData()))},initialData:o})};var oe=tinymce.util.Tools.resolve("tinymce.Env");const ae=e=>{const t=e.name;return"iframe"===t||"video"===t||"audio"===t},se=(e,t,r,o=null)=>{const a=e.attr(r);return s(a)?a:h(t,r)?null:o},ie=(e,t,r)=>{const o="img"===t.name||"video"===e.name,a=o?"300":null,s="audio"===e.name?"30":"150",i=o?s:null;t.attr({width:se(e,r,"width",a),height:se(e,r,"height",i)})},ne=(e,t)=>{const r=t.name,o=new D("img",1);return ce(e,t,o),ie(t,o,{}),o.attr({style:t.attr("style"),src:oe.transparentSrc,"data-mce-object":r,class:"mce-object mce-object-"+r}),o},le=(e,t)=>{var r;const o=t.name,a=new D("span",1);a.attr({contentEditable:"false",style:t.attr("style"),"data-mce-object":o,class:"mce-preview-object mce-object-"+o}),ce(e,t,a);const i=e.dom.parseStyle(null!==(r=t.attr("style"))&&void 0!==r?r:""),n=new D(o,1);if(ie(t,n,i),n.attr({src:t.attr("src"),style:t.attr("style"),class:t.attr("class")}),"iframe"===o)n.attr({allowfullscreen:t.attr("allowfullscreen"),frameborder:"0",sandbox:t.attr("sandbox"),referrerpolicy:t.attr("referrerpolicy")});else{l(["controls","crossorigin","currentTime","loop","muted","poster","preload"],(e=>{n.attr(e,t.attr(e))}));const r=a.attr("data-mce-html");s(r)&&((e,t,r,o)=>{const a=M(e.schema).parse(o,{context:t});for(;a.firstChild;)r.append(a.firstChild)})(e,o,n,unescape(r))}const c=new D("span",1);return c.attr("class","mce-shim"),a.append(n),a.append(c),a},ce=(e,t,r)=>{var o;const a=null!==(o=t.attributes)&&void 0!==o?o:[];let s=a.length;for(;s--;){const t=a[s].name;let o=a[s].value;"width"===t||"height"===t||"style"===t||(n="data-mce-",(i=t).length>=9&&i.substr(0,9)===n)||("data"!==t&&"src"!==t||(o=e.convertURL(o,t)),r.attr("data-mce-p-"+t,o))}var i,n;const c=F({inner:!0},e.schema),m=new D("div",1);l(t.children(),(e=>m.append(e)));const u=c.serialize(m);u&&(r.attr("data-mce-html",escape(u)),r.empty())},me=e=>{const t=e.attr("class");return r(t)&&/\btiny-pageembed\b/.test(t)},ue=e=>{let t=e;for(;t=t.parent;)if(t.attr("data-ephox-embed-iri")||me(t))return!0;return!1},de=(e,t,r)=>{const o=(0,e.options.get)("xss_sanitization"),a=f(e);return M(e.schema,{sanitize:o,validate:a}).parse(r,{context:t})},he=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("media",(e=>((e=>{const t=e.options.register;t("audio_template_callback",{processor:"function"}),t("video_template_callback",{processor:"function"}),t("iframe_template_callback",{processor:"function"}),t("media_live_embeds",{processor:"boolean",default:!0}),t("media_filter_html",{processor:"boolean",default:!0}),t("media_url_resolver",{processor:"function"}),t("media_alt_source",{processor:"boolean",default:!0}),t("media_poster",{processor:"boolean",default:!0}),t("media_dimensions",{processor:"boolean",default:!0})})(e),(e=>{e.addCommand("mceMedia",(()=>{re(e)}))})(e),(e=>{const t=()=>e.execCommand("mceMedia");e.ui.registry.addToggleButton("media",{tooltip:"Insert/edit media",icon:"embed",onAction:t,onSetup:t=>{const r=e.selection;t.setActive(W(r.getNode()));const o=r.selectorChangedWithUnbind("img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]",t.setActive).unbind,a=he(e)(t);return()=>{o(),a()}}}),e.ui.registry.addMenuItem("media",{icon:"embed",text:"Media...",onAction:t,onSetup:he(e)})})(e),(e=>{e.on("ResolveName",(e=>{let t;1===e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}))})(e),(e=>{e.on("PreInit",(()=>{const{schema:t,serializer:r,parser:o}=e,a=t.getBoolAttrs();l("webkitallowfullscreen mozallowfullscreen".split(" "),(e=>{a[e]={}})),((e,t)=>{const r=m(e);for(let o=0,a=r.length;o{const o=t.getElementRule(r);o&&l(e,(e=>{o.attributes[e]={},o.attributesOrder.push(e)}))})),o.addNodeFilter("iframe,video,audio,object,embed",(e=>t=>{let r,o=t.length;for(;o--;)r=t[o],r.parent&&(r.parent.attr("data-mce-object")||(ae(r)&&v(e)?ue(r)||r.replace(le(e,r)):ue(r)||r.replace(ne(e,r))))})(e)),r.addAttributeFilter("data-mce-object",((t,r)=>{var o;let a=t.length;for(;a--;){const s=t[a];if(!s.parent)continue;const i=s.attr(r),n=new D(i,1);if("audio"!==i){const e=s.attr("class");e&&-1!==e.indexOf("mce-preview-object")&&s.firstChild?n.attr({width:s.firstChild.attr("width"),height:s.firstChild.attr("height")}):n.attr({width:s.attr("width"),height:s.attr("height")})}n.attr({style:s.attr("style")});const c=null!==(o=s.attributes)&&void 0!==o?o:[];let m=c.length;for(;m--;){const e=c[m].name;0===e.indexOf("data-mce-p-")&&n.attr(e.substr(11),c[m].value)}const u=s.attr("data-mce-html");if(u){const t=de(e,i,unescape(u));l(t.children(),(e=>n.append(e)))}s.replace(n)}}))})),e.on("SetContent",(()=>{const t=e.dom;l(t.select("span.mce-preview-object"),(e=>{0===t.select("span.mce-shim",e).length&&t.add(e,"span",{class:"mce-shim"})}))}))})(e),(e=>{e.on("mousedown",(t=>{const r=e.dom.getParent(t.target,".mce-preview-object");r&&"2"===e.dom.getAttrib(r,"data-mce-selected")&&t.stopImmediatePropagation()})),e.on("click keyup touchend",(()=>{const t=e.selection.getNode();t&&e.dom.hasClass(t,"mce-preview-object")&&e.dom.getAttrib(t,"data-mce-selected")&&t.setAttribute("data-mce-selected","2")})),e.on("ObjectResized",(t=>{const r=t.target;if(r.getAttribute("data-mce-object")){let o=r.getAttribute("data-mce-html");o&&(o=unescape(o),r.setAttribute("data-mce-html",escape(U(o,{width:String(t.width),height:String(t.height)},!1,e.schema))))}}))})(e),(e=>({showDialog:()=>{re(e)}}))(e))))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/nonbreaking/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/nonbreaking/plugin.min.js new file mode 100644 index 0000000..3b8f8bd --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/nonbreaking/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,o=e("boolean"),a=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),s=t("nonbreaking_wrap"),r=(n,e)=>{let o="";for(let a=0;a{const o=s(n)||n.plugins.visualchars?`${r(" ",e)}`:r(" ",e);n.undoManager.transact((()=>n.insertContent(o)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");const u=n=>e=>{const o=()=>{e.setEnabled(n.selection.isEditable())};return n.on("NodeChange",o),o(),()=>{n.off("NodeChange",o)}};n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>o(n)?{value:n?3:0,valid:!0}:a(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e,onSetup:u(n)}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e,onSetup:u(n)})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(o=>{if(o.keyCode===l.TAB&&!o.isDefaultPrevented()){if(o.shiftKey)return;o.preventDefault(),o.stopImmediatePropagation(),c(n,e)}}))})(n)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/pagebreak/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/pagebreak/plugin.min.js new file mode 100644 index 0000000..0e2f755 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/pagebreak/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),n=t("pagebreak_separator"),o=t("pagebreak_split_block"),r="mce-pagebreak",s=e=>{const t=``;return e?`

    ${t}

    `:t},c=e=>a=>{const t=()=>{a.setEnabled(e.selection.isEditable())};return e.on("NodeChange",t),t(),()=>{e.off("NodeChange",t)}};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(o(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a,onSetup:c(e)}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a,onSetup:c(e)})})(e),(e=>{const a=n(e),t=()=>o(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(n=>{let o,s,c=n.length;for(;c--;)if(o=n[c],s=o.attr("class"),s&&-1!==s.indexOf(r)){const n=o.parent;if(n&&e.schema.getBlockElements()[n.name]&&t()){n.type=3,n.value=a,n.raw=!0,o.remove();continue}o.type=3,o.value=a,o.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,r)&&(a.name="pagebreak")}))})(e)}))}(); \ No newline at end of file diff --git a/idrocap_wa/webroot/js/tinymce/plugins/preview/plugin.min.js b/idrocap_wa/webroot/js/tinymce/plugins/preview/plugin.min.js new file mode 100644 index 0000000..e1f4df3 --- /dev/null +++ b/idrocap_wa/webroot/js/tinymce/plugins/preview/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 7.3.0 (2024-08-07) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='"})),d&&(l+='");const y=r(e),u=c(e),v='